Вход Регистрация
Файл: core/functions/placeholders_functions.php
Строк: 58
<?php
#####################################
# ShopCMS: Скрипт интернет-магазина
# Copyright (c) by ADGroup
# http://shopcms.ru
#####################################

// При ошибке в sql_placeholder_ex() возвращается запрос с
// указанным ниже префиксом.
@define("PLACEHOLDER_ERROR_PREFIX""ERROR: ");

// function sql_compile_placeholder(string $tmpl)
// Разбирает шаблон запроса и сохраняет положения всех
// placeholder-ов в нем для дальнейшей быстрой подстановки.
// Возвращает структуру вида:
// list(
//   list(
//     $key,    // имя placeholder-а
//     $type,   // '@'|'%'|'#'|''
//     $start,  // положение placeholder-а
//     $length  // длина placeholder-а
//   ),
//   $tmpl,     // исходный шаблон запроса
//   $has_named // есть ли в шаблоне именованный placeholder?
// )
function sql_compile_placeholder($tmpl) {
  
$compiled  = array();
  
$p         0;  // текущая позиция в строке
  
$i         0;  // счетчик placeholder-ов
  
$has_named false;
  while (
false !== ($start $p strpos($tmpl"?"$p))) {
    
// Определяем тип placeholder-а.
    
switch ($c substr($tmpl, ++$p1)) {
      case 
'%': case '@': case '#': case '&':
        
$type $c; ++$p; break;
      default:
        
$type ''; break;
    }
    
// Проверяем, именованный ли это placeholder: "?keyname"
    
if (preg_match('/^((?:[^s[:punct:]]|_)+)/'substr($tmpl$p), $pock)) {
      
$key $pock[1];
      if (
$type != '#'$has_named true;
      
$p += strlen($key);
    } else {
      
$key $i;
      if (
$type != '#'$i++;
    }
    
// Сохранить запись о placeholder-е.
    
$compiled[] = array($key$type$start$p $start);
  }
  return array(
$compiled$tmpl$has_named);
}


// bool sql_placeholder_ex(mixed $tmpl, array $args, string &$errormsg)
//
// Заменяет все placeholder-ы в $tmpl на их SQL-экранированные значения
// из $args. При ошибке сохраняет диагностическое сообщение в $errormsg.
//
// Различные типы placeholder-ов:
//   ?  - заменяется на ОДНО скалярное значение.
//   ?@ - заменяется на СПИСОК: 'a', 'b', ... (например, удобно
//        использовать в запросе "SELECT ... WHERE id IN (?@)")
//   ?% - заменяется на список пар ключ=значение: k1='v1', k2='v2', ...
//        (удобно использовать в запросах "UPDATE ... SET ?%")
//
// Placeholder-ы могут быть именованными: их имя можно указывать сразу
// после спецификатора типа, например: "?k", "?@k", "?%k".
//
// Параметр $tmpl может содержать не только текстовое представление
// шаблона, но и результат работы функции sql_compile_placeholder().
// Это удобно, если нужно несколько раз выполнить SQL-запрос, имеющий
// один и тот же шаблон, но разные параметры.
//
// Если в шаблоне есть хотя бы один именованный placeholder,
// $args должен содержать список из ЕДИНСТВЕННОГО элемента. Этот
// элемент сам является ассоциативным массивом, содержащим имена
// placeholder-ов и соответствующие им значения.
//
// Если при подстановке  возникнут ошибки (например, несоответствие
// типов placeholder-а и подставляемого значения, недопустимое имя
// или номер placeholder-а и т.д.), в результирующий запрос вместо
// значения placeholder-а вставляется диагностическое сообщение.
// При этом функция возвращает false, а получившийся "фальшивый"
// запрос помещается в переменную $errormsg.
function sql_placeholder_ex($tmpl$args, &$errormsg) {
  
// Запрос уже разобран?.. Если нет, разбираем.
  
if (is_array($tmpl)) {
    
$compiled $tmpl;
  } else {
    
$compiled  sql_compile_placeholder($tmpl);
  }

  list (
$compiled$tmpl$has_named) = $compiled;

  
// Если есть хотя бы один именованный placeholder, используем
  // первый аргумент в качестве ассоциативного массива.
  
if ($has_named$args = @$args[0];

  
// Выполняем все замены в цикле.
  
$p   0;       // текущее положение в строке
  
$out '';      // результирующая строка
  
$error false// были ошибки?

  
foreach ($compiled as $num=>$e) {
    list (
$key$type$start$length) = $e;

    
// Pre-string.
    
$out .= substr($tmpl$p$start $p);
    
$p $start $length;

    
$repl '';   // текст для замены текущего placeholder-а
    
$errmsg ''// сообщение об ошибке для этого placeholder-а
    
do {
      
// Это placeholder-константа?
      
if ($type === '#') {
        
$repl = @constant($key);
        if (
NULL === $repl)
          
$error $errmsg "UNKNOWN_CONSTANT_$key";
        break;
      }
      
// Обрабатываем ошибку.
      
if (!isset($args[$key])) {
        
$error $errmsg "UNKNOWN_PLACEHOLDER_$key";
        break;
      }
      
// Вставляем значение в соответствии с типом placeholder-а.
      
$a $args[$key];
      if (
$type === '') {
        
// Скалярный placeholder.
        
if (is_array($a)) {
          
$error $errmsg "NOT_A_SCALAR_PLACEHOLDER_$key";
          break;
        }
        
$repl preg_match('/^d+$/'$a)? $a "'".addslashes($a)."'";
        break;
      }
      
// Иначе это массив или список.
      
if (!is_array($a)) {
        
$error $errmsg "NOT_AN_ARRAY_PLACEHOLDER_$key";
        break;
      }
      if (
$type === '@') {
        
// Это список.
        
foreach ($a as $v)
          
$repl .= ($repl===''"" ",")."'".addslashes($v)."'";
      } elseif (
$type === '%') {
        
// Это набор пар ключ=>значение.
        
$lerror = array();
        foreach (
$a as $k=>$v) {
          if (!
is_string($k)) {
            
$lerror[$k] = "NOT_A_STRING_KEY_{$k}_FOR_PLACEHOLDER_$key";
          } else {
            
$k preg_replace('/[^a-zA-Z0-9_]/''_'$k);
          }
          
$repl .= ($repl===''"" ", ").$k."='".@addslashes($v)."'";
        }
        
// Если была ошибка, составляем сообщение.
        
if (count($lerror)) {
          
$repl '';
          foreach (
$a as $k=>$v) {
            if (isset(
$lerror[$k])) {
              
$repl .= ($repl===''"" ", ").$lerror[$k];
            } else {
              
$k preg_replace('/[^a-zA-Z0-9_-]/''_'$k);
              
$repl .= ($repl===''"" ", ").$k."=?";
            }
          }
          
$error $errmsg $repl;
        }
      } elseif (
$type === '&'){

                        
// Это список.
                        
foreach ($a as $v)
                        
$repl .= ($repl===''"" ",").'`'.addslashes($v).'`';
      }
    } while (
false);
    if (
$errmsg$compiled[$num]['error'] = $errmsg;
    if (!
$error$out .= $repl;
  }
  
$out .= substr($tmpl$p);

  
// Если возникла ошибка, переделываем результирующую строку
  // в сообщение об ошибке (расставляем диагностические строки
  // вместо ошибочных placeholder-ов).
  
if ($error) {
    
$out '';
    
$p   0;       // текущая позиция
    
foreach ($compiled as $num=>$e) {
      list (
$key$type$start$length) = $e;
      
$out .= substr($tmpl$p$start $p);
      
$p $start $length;
      if (isset(
$e['error'])) {
        
$out .= $e['error'];
      } else {
        
$out .= substr($tmpl$start$length);
      }
    }
    
// Последняя часть строки.
    
$out .= substr($tmpl$p);
    
$errormsg $out;
    return 
false;
  } else {
    
$errormsg false;
    return 
$out;
  }
}


// function sql_placeholder(mixed $tmpl, $arg1 [,$arg2 ...])
//
// Замечание: см. описание функции sql_placeholder_ex() выше.
//
// Возвращает результирующий запрос после всех подстановок.
// В случае ошибки запрос будет содержать префикс "ERROR: ".
//
// Если во время подстановки произошла ошибка, (например, несоответствие
// типов), вставляет вместо значений placeholder-ов текстовое сообщение
// об ошибке и возвращает запрос в следующем виде:
//   "ERROR: шаблон с проставленными сообщениями".
// Такой запрос, конечно, породит ошибку при попытке своего выполнения.
// Вы также можете проанализировать возвращаенное значение: если оно
// начинается со строки "ERROR: ", подстановка окончилась неудачей.
//
// Вместо того, чтобы использовать массив в качестве второго параметра,
// вы можете передать значения всех неименованных placeholder-ов одно
// за одним.
//
// Если же в шаблоне есть хотя бы один именованный placeholder, функция
// ОБЯЗАНА принимать в точности два параметра, где первый - это шаблон,
// а второй - ассоциативный массив для подстановки значений именованных
// placeholder-ов.
function sql_placeholder() {
  
$args func_get_args();
  
$tmpl array_shift($args);
  
$result sql_placeholder_ex($tmpl$args$error);
  if (
$result === false) return PLACEHOLDER_ERROR_PREFIX.$error;
  else return 
$result;
}


// function sql_pholder(mixed $tmpl, $arg1 [,$arg2 ...])
//
// Замечание: см. описание функции sql_placeholder() выше.
//
// Функция работает точно так же, как sql_placeholder(), однако
// в случае ошибки она возвращает false и генерирует предупреждение
// стандартными средствами, используя trigger_error().
function sql_pholder() {
  
$args func_get_args();
  
$tmpl array_shift($args);
  
$result sql_placeholder_ex($tmpl$args$error);
  if (
$result === false) {
    
$error "Placeholder substitution error. Diagnostics: "$error"";
    if (
function_exists("debug_backtrace")) {
      
$bt debug_backtrace();
      
$error .= " in ".@$bt[0]['file']." on line ".@$bt[0]['line'];
    }
    
trigger_error($errorE_USER_WARNING);
    return 
false;
  }
  return 
$result;
}

?>
Онлайн: 1
Реклама