...

среда, 8 мая 2019 г.

[recovery mode] Призрачные SQL запросы

Взгляните на код PHP:
$user->v_useragent = 'coresky.agent';

Такой код может спровоцировать SQL запрос UPDATE или INSERT, а может и не спровоцировать если идентичные данные уже установлены в БД, собственно поэтому этот функционал именуется «Призрачные SQL запросы». Дело в том, что этот функционал, направлен на то что вначале работы скрипта, часто будет происходить чтение из ячейки БД, а потом возможна запись. Он имеет потенциал довольно широко применяться в веб-приложениях, особенно в тех, где не используется ORM, но я не видел чтобы он был где-то описан. ORM обычно имеют встроенные похожие алгоритмы. Давайте разберемся в деталях, что есть хорошо и что плохо в описываемом функционале.
В коде для повторного использования, для организации «призрачных запросов» необходимо иметь три метода, первый приведу полностью, так как он довольно прост:
class SKY // код из проекта coresky
{
...
  static function &ghost($char, $original, $sql = '', $flag = 0) {
    SKY::$mem[$char] = [$flag, $flag & 4 ? null : $original, $sql, []];
    if ($sql)
      trace('GHOST SQL: ' . (is_array($sql) ? end($sql) : $sql), false, 1);
    if ($original) foreach (explode("\n", unl($original)) as $v) {
      list($k, $v) = explode(' ', $v, 2);
      SKY::$mem[$char][3][$k] = unescape($v, true);
    }
    return SKY::$mem[$char][3];
  }


Входные параметры метода:
  • $char — одна маленькая буква английского алфавита, указывает на тип функционала призрачных запросов, может использоваться в префиксах переменных, как в примере выше;
  • $original — текстовое содержимое ячейки БД (`mediumtext` для MySQL), где скопом хранятся все переменные призрачных запросов $char. На вход может подаваться и пустая строка;
  • $sql — шаблон запроса, который будет использоваться для генерации реального SQL запроса, например в callback функции для register_shutdown_function();
  • $flag — флаг. Чаще используется предустановленное значение 0;

Шаблоны запроса могут быть двух типов, на основе функций sql(..) или sqlf(..). Код второй приведу полностью, так как он, при правильном использовании, гарантирует невозможность SQL инъекций, он быстр и довольно прост:
function sqlf() { # quick parsing, using printf syntax. No SQL injection!
  $in = func_get_args();
  $tpl = array_shift($in);
  if ($pos = strpos($tpl, '$'))
    $tpl = preg_replace('/\$_(\w+)/', T_PREFIX . '$1', $tpl);
  
  $sql = vsprintf($tpl, array_map(function ($a) {
    if (!is_array($a))
      return is_num($a) ? $a : escape($a); # just escape ALL parameters if not numeric
    return implode(', ', array_map(function ($v) {
      return is_num($v) ? $v : escape($v); # just escape ALL parameters if not numeric
    }, $a));
  }, $in));

  return sql(1, $sql);
}

К сожалению, функция sqlf() не универсальна, с точки зрения составления произвольных SQL запросов в аспекте защиты от инъекций. Однако она существует параллельно с универсальной функцией sql(), из-за сравнительно высокой скорости работы. Шаблоны для sqlf() используются для случая работы только лишь с одной ячейкой mediumtext. Второй же шаблон, используется когда нужно организовать такие отложенные запросы для многих колонок таблицы.

Как происходит обработка, указанного кода PHP в самом начале статьи


Переменная $user содержит указатель на объект USER, который, в свою очередь, имеет магические методы __get() и __set(). По префиксу v_ класс понимает, что происходит запись в таблицу сессий `visitors` и вызыват метод SKY::save(..) который сохраняет код в массиве SKY::$mem. По окончанию работы скрипта, вызывается callback функция для register_shutdown_function(), в котором собственно осуществляется (или нет) реальный SQL запрос в БД.

Итак, остальные два метода, которые необходимы для организации функционала, это SKY::save(..) и SKY::here(..). Первый сохраняет данные в массив, а второй генерирует и выполняет реальный запрос в БД.

В коде coresky (повторно используемый код фреймворк или CMF) используется 8 типов призрачных SQL:

  • системная конфигурация, которая хранится в БД;
  • конфигурация посетителей;
  • конфигурация авторизованных пользователей;
  • системная конфигурация админки;
  • системная конфигурация консольных запусков;
  • три типа призрачных SQL используются для организации утилиты i18n;

Как видим «призрачные SQL» актуальны практически для всех web-приложений.

Достоинства описываемого функционала


  • не нужно делать LATER TABLE… (или INSERT новых рядов) чтобы добавить новые переменные конфигураций, когда приложение развивается. Можно добавлять новые переменные просто в PHP коде, не изменяя структуру БД;
  • функционал может сократить количество запросов к БД до одного, для случая когда происходит запись в один и тот-же ряд одной и той же таблицы;

Недостаток


Для переменных ghost SQL нельзя «прикрутить» индексы, скорее всего, нельзя сделать LOCK TABLE или использовать другие расширенные возможности MySQL.

Больше информации можно прочесть на сайте проекта SKY

Let's block ads! (Why?)

Комментариев нет:

Отправить комментарий