Отримання необробленого рядка запиту SQL з готових операторів PDO


130

Чи існує спосіб отримати необроблений рядок SQL при виклику PDOStatement :: Execute () на підготовлений оператор? Для налагодження це було б дуже корисно.



1
Перевірте одно рядкову функцію pdo-debug .
Sliq

Найчистіший спосіб, який я знайшов, - це бібліотека E_PDOStatement . Ви просто робите $stmt = $pdo->prepare($query); /* ... */ echo $stmt->fullQuery;. Це працює за допомогою розширення класу PDOStatement , отже, настільки ж елегантно, як дозволяє PDO API.
ComFreek

Відповіді:


110

Я припускаю, що ви маєте на увазі, що ви хочете остаточний запит SQL із значеннями параметрів, інтерпольованими в нього. Я розумію, що це було б корисно для налагодження, але це не так, як працюють підготовлені заяви. Параметри не поєднуються з підготовленою заявою на стороні клієнта, тому PDO ніколи не повинен мати доступ до рядка запиту в поєднанні з його параметрами.

Оператор SQL надсилається на сервер бази даних, коли ви готуєте (), а параметри надсилаються окремо при виконанні (). Загальний журнал запитів MySQL показує кінцевий SQL зі значеннями, інтерпольованими після виконання (). Нижче наведено уривок із мого загального журналу запитів. Я виконував запити від mysql CLI, а не з PDO, але принцип той самий.

081016 16:51:28 2 Query       prepare s1 from 'select * from foo where i = ?'
                2 Prepare     [2] select * from foo where i = ?
081016 16:51:39 2 Query       set @a =1
081016 16:51:47 2 Query       execute s1 using @a
                2 Execute     [2] select * from foo where i = 1

Ви також можете отримати те, що хочете, якщо встановити атрибут PDO PDO :: ATTR_EMULATE_PREPARES. У цьому режимі PDO інтерполює параметри в SQL-запит і надсилає весь запит під час виконання (). Це не справжній підготовлений запит. Ви обходите переваги підготовлених запитів, інтерполюючи змінні в рядок SQL перед виконанням ().


Re коментар від @afilina:

Ні, текстовий запит SQL не поєднується з параметрами під час виконання. Тож PDO нічого не показує.

Внутрішньо, якщо ви використовуєте PDO :: ATTR_EMULATE_PREPARES, PDO робить копію запиту SQL та інтерполює в нього значення параметрів, перш ніж підготувати та виконати. Але PDO не виставляє цього зміненого запиту SQL.

Об'єкт PDOStatement має властивість $ queryString, але це встановлюється лише в конструкторі для PDOStatement, і він не оновлюється, коли запит буде переписаний з параметрами.

Було б розумним запитом на функцію PDO, щоб вони попросили їх викласти переписаний запит. Але навіть це не дасть вам "повного" запиту, якщо ви не використовуєте PDO :: ATTR_EMULATE_PREPARES.

Ось чому я показую вище вирішення питання використання загального журналу запитів сервера MySQL, тому що в цьому випадку навіть підготовлений запит із заповнювачами параметрів переписується на сервер із значеннями параметрів, заповненими в рядок запиту. Але це робиться лише під час ведення журналу, а не під час виконання запитів.


10
І як ви отримуєте запит на дірочки, коли для PDO :: ATTR_EMULATE_PREPARES встановлено значення TRUE?
Ясен Желев

2
@ Ясен Желєв: Якщо PDO емуляція готує, то вона буде інтерполювати значення параметрів у запит, перш ніж готувати запит. Отже MySQL ніколи не бачить версію запиту із заповнювачами параметрів. MySQL реєструє лише повний запит.
Білл Карвін

2
@ Білл: "Параметри не поєднуються з підготовленою заявою на стороні клієнта" - зачекайте - але чи поєднуються вони на стороні сервера? Або як mysql вставляє значення в БД?
Стенн

1
@afilina, ні, ти не можеш. Дивіться моє пояснення вище.
Білл Карвін

3
Нічого собі, голова? Будь ласка, не стріляйте в месенджер. Я просто описую, як це працює.
Білл Карвін

107
/**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public static function interpolateQuery($query, $params) {
    $keys = array();

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }
    }

    $query = preg_replace($keys, $params, $query, 1, $count);

    #trigger_error('replaced '.$count.' keys');

    return $query;
}

6
чому б не просто використовувати strtr(): швидше, простіше, ті самі результати. strtr($query, $params);
Тоні Чібукас

Яке використання для цього?

Просто хотів зупинитися і запропонувати свою подяку, був поза цілим додатковим класом за це, який я зараз зняв на користь цього, оскільки це крихітний та блискучий :). Тож чорт корисний для дебютування всіх запитів, які виконує додаток на кожній сторінці,
заносячи

Бачив цю функцію , і це зробило мене дуже щасливим, хоча, що - то я не розумію, чому ви перевірити $keyдля того , щоб бути stringі не $value? Я щось пропускаю? Причина, яку я запитую, це через те, що цей вихід, другий параметр не сприймається як рядок:string(115) "INSERT INTO tokens (token_type, token_hash, user_id) VALUES ('resetpassword', hzFs5RLMpKwTeShTjP9AkTA2jtxXls86, 1);"
Kerwin Sneijders,

1
Це хороший початок, але він не вдається, якщо значення парам $ сам включає знак питання ("?").
куріччі

32

Я змінив метод, щоб включити обробку вихідних масивів для операторів типу WHERE IN (?).

ОНОВЛЕННЯ: Просто додано перевірку на значення NULL та дублювання $ params, щоб фактичні значення $ param не змінювалися.

Чудова робота bigwebguy і спасибі!

/**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public function interpolateQuery($query, $params) {
    $keys = array();
    $values = $params;

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }

        if (is_string($value))
            $values[$key] = "'" . $value . "'";

        if (is_array($value))
            $values[$key] = "'" . implode("','", $value) . "'";

        if (is_null($value))
            $values[$key] = 'NULL';
    }

    $query = preg_replace($keys, $values, $query);

    return $query;
}

2
Я думаю, що ти повинен робити $values = $params;замість цього $values = array().
тестування

Ще один невеликий твір, який тут пропущено, - це струни. Для того, щоб зафіксувати це, поставте це над is_arrayперевіркою:if (is_string($value)) $values[$key] = "'" . $value . "'";
woodface

Це лише обмежене значення прив'язки до лише одного разу у preg_replace. додайте цей рядок після $values = $params; $values_limit = []; $words_repeated = array_count_values(str_word_count($sql, 1, ':_')); додавання цього внутрішнього спершу, якщо в foreach, $values_limit[$key] = (isset($words_repeated[':'.$key]) ? intval($words_repeated[':'.$key]) : 1);а це в першому іншому в foreach, $values_limit = [];використовуйте значення foreach loop $ знову для preg_replace зisset($values_limit[$key])
vee

наприклад, циклічні значення $. if (is_array($values)) { foreach ($values as $key => $val) { if (isset($values_limit[$key])) { $sql = preg_replace(['/:'.$key.'/'], [$val], $sql, $values_limit[$key], $count); } } unset($key, $val); } else { $sql = preg_replace($keys, $values, $sql, 1, $count); }
vee

12

Трохи пізно, мабуть, але зараз є PDOStatement::debugDumpParams

Зберігає інформацію, що міститься в підготовленому виписці, безпосередньо на виході. Він надасть запит SQL, що використовується, кількість використаних параметрів (Params), список параметрів, їх ім'я, тип (парамтип) у вигляді цілого числа, їх ключове ім’я чи позицію та позицію в запиті (якщо це підтримується драйвером PDO, інакше це буде -1).

Більше можна знайти на офіційних документах php

Приклад:

<?php
/* Execute a prepared statement by binding PHP variables */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindValue(':colour', $colour, PDO::PARAM_STR, 12);
$sth->execute();

$sth->debugDumpParams();

?>


та для кращої читабельності:echo '<pre>'; $sth->debugDumpParams(); echo '</pre>';
SandroMarques

10

Рішення полягає у добровільному введенні помилки у запиті та друкуванні повідомлення про помилку:

//Connection to the database
$co = new PDO('mysql:dbname=myDB;host=localhost','root','');
//We allow to print the errors whenever there is one
$co->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

//We create our prepared statement
$stmt = $co->prepare("ELECT * FROM Person WHERE age=:age"); //I removed the 'S' of 'SELECT'
$stmt->bindValue(':age','18',PDO::PARAM_STR);
try {
    $stmt->execute();
} catch (PDOException $e) {
    echo $e->getMessage();
}

Стандартний вихід:

SQLSTATE [42000]: Помилка синтаксису або порушення доступу: [...] біля "ELECT * FROM Person WHERE age = 18" у рядку 1

Важливо зазначити, що він друкує лише перші 80 символів запиту.


Я не знаю, чому це було знято. Це просто і працює. Це працює швидко. Набагато швидше, ніж увімкнути журнал, шукати потрібний рядок у журналі, потім вимкнути журнал, потім очистити файли журналу.
Боян Хрнкас

@BojanHrnkas тривалість вибірки помилок дуже обмежена. Для такого простого запиту простіше замінити заповнювач із змінною просто вручну. І цей метод працює лише в тому випадку, якщо ви включили емуляцію.
Твій здоровий глузд

9

Додано трохи більше до коду Майка - пройдіть значення, щоб додати одиничні лапки

/**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public function interpolateQuery($query, $params) {
    $keys = array();
    $values = $params;

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }

        if (is_array($value))
            $values[$key] = implode(',', $value);

        if (is_null($value))
            $values[$key] = 'NULL';
    }
    // Walk the array to see if we can add single-quotes to strings
    array_walk($values, create_function('&$v, $k', 'if (!is_numeric($v) && $v!="NULL") $v = "\'".$v."\'";'));

    $query = preg_replace($keys, $values, $query, 1, $count);

    return $query;
}

1
Дуже корисно, я зробив деякі модифікації , щоб перевизначити bindParam функцію PDOStatement класу і перевірки , якщо значення є рядком або цілим числом з PDO: Params значення.
Серхіо Флорес

де ми можемо це побачити?
Мауг каже, що повернемо Моніку

8

PDOStatement має загальнодоступну власність $ queryString. Це має бути те, що ви хочете.

Я щойно помітив, що PDOStatement має незадокументований метод debugDumpParams (), який ви також можете поглянути.


1
У debugDumpParams немає документально підтверджених php.net/manual/en/pdostatement.debugdumpparams.php
mloskot

Ні. $ queryString не показує включені значення парам.
Андреас

5

Ви можете розширити клас PDOStatement, щоб захопити обмежені змінні та зберігати їх для подальшого використання. Тоді можуть бути додані два способи, один для санітарної змінної (debugBindedVariables) та інший для друку запиту за допомогою цих змінних (debugQuery):

class DebugPDOStatement extends \PDOStatement{
  private $bound_variables=array();
  protected $pdo;

  protected function __construct($pdo) {
    $this->pdo = $pdo;
  }

  public function bindValue($parameter, $value, $data_type=\PDO::PARAM_STR){
    $this->bound_variables[$parameter] = (object) array('type'=>$data_type, 'value'=>$value);
    return parent::bindValue($parameter, $value, $data_type);
  }

  public function bindParam($parameter, &$variable, $data_type=\PDO::PARAM_STR, $length=NULL , $driver_options=NULL){
    $this->bound_variables[$parameter] = (object) array('type'=>$data_type, 'value'=>&$variable);
    return parent::bindParam($parameter, $variable, $data_type, $length, $driver_options);
  }

  public function debugBindedVariables(){
    $vars=array();

    foreach($this->bound_variables as $key=>$val){
      $vars[$key] = $val->value;

      if($vars[$key]===NULL)
        continue;

      switch($val->type){
        case \PDO::PARAM_STR: $type = 'string'; break;
        case \PDO::PARAM_BOOL: $type = 'boolean'; break;
        case \PDO::PARAM_INT: $type = 'integer'; break;
        case \PDO::PARAM_NULL: $type = 'null'; break;
        default: $type = FALSE;
      }

      if($type !== FALSE)
        settype($vars[$key], $type);
    }

    if(is_numeric(key($vars)))
      ksort($vars);

    return $vars;
  }

  public function debugQuery(){
    $queryString = $this->queryString;

    $vars=$this->debugBindedVariables();
    $params_are_numeric=is_numeric(key($vars));

    foreach($vars as $key=>&$var){
      switch(gettype($var)){
        case 'string': $var = "'{$var}'"; break;
        case 'integer': $var = "{$var}"; break;
        case 'boolean': $var = $var ? 'TRUE' : 'FALSE'; break;
        case 'NULL': $var = 'NULL';
        default:
      }
    }

    if($params_are_numeric){
      $queryString = preg_replace_callback( '/\?/', function($match) use( &$vars) { return array_shift($vars); }, $queryString);
    }else{
      $queryString = strtr($queryString, $vars);
    }

    echo $queryString.PHP_EOL;
  }
}


class DebugPDO extends \PDO{
  public function __construct($dsn, $username="", $password="", $driver_options=array()) {
    $driver_options[\PDO::ATTR_STATEMENT_CLASS] = array('DebugPDOStatement', array($this));
    $driver_options[\PDO::ATTR_PERSISTENT] = FALSE;
    parent::__construct($dsn,$username,$password, $driver_options);
  }
}

І тоді ви можете використовувати цей успадкований клас для налагодження пурпурів.

$dbh = new DebugPDO('mysql:host=localhost;dbname=test;','user','pass');

$var='user_test';
$sql=$dbh->prepare("SELECT user FROM users WHERE user = :test");
$sql->bindValue(':test', $var, PDO::PARAM_STR);
$sql->execute();

$sql->debugQuery();
print_r($sql->debugBindedVariables());

У результаті

ВИБІР користувача з користувачів WHERE user = 'user_test'

Масив ([: test] => user_test)


4

Я витратив чимало часу на дослідження цієї ситуації для власних потреб. Цей та декілька інших потоків SO дуже допомогли мені, тому я хотів поділитися тим, що я придумав.

Хоча доступ до інтерпольованого рядка запитів є суттєвою перевагою під час усунення несправностей, ми хотіли мати можливість підтримувати журнал лише певних запитів (тому використання журналів бази даних для цієї мети було не ідеальним). Ми також хотіли мати можливість використовувати журнали для відновлення стану таблиць у будь-який момент часу, тому нам потрібно було впевнитись, що інтерпольовані рядки були належним чином усунені. Нарешті, ми хотіли розширити цю функціональність на всю нашу кодову базу, вимагаючи переписати якомога менше її (терміни, маркетинг та інше; ви знаєте, як це).

Моє рішення полягало в тому, щоб розширити функціональність об'єкта PDOStatement за замовчуванням для кешування параметризованих значень (або посилань), і коли оператор виконується, використовувати функціональність об'єкта PDO для належного виходу з параметрів, коли вони вводяться назад у запит рядок. Потім ми можемо прив’язатись до виконання об’єкта оператора та записати фактичний запит, який був виконаний у той час ( або хоча б максимально вірний репродукції) .

Як я вже говорив, ми не хотіли змінювати всю базу коду, щоб додати цю функціональність, тому ми перезаписуємо стандартні типи bindParam()та bindValue()методи об’єкта PDOStatement, робимо кешування зв'язаних даних, а потім виклик parent::bindParam()або батьківський :: bindValue(). Це дозволило нашій існуючій кодовій базі продовжувати функціонувати як нормально.

Нарешті, коли execute()метод викликається, ми виконуємо нашу інтерполяцію і надаємо результуючу рядок як нову властивість E_PDOStatement->fullQuery. Це може бути результатом для перегляду запиту або, наприклад, записаного у файл журналу.

Розширення разом із інструкціями щодо встановлення та налаштування доступні на github:

https://github.com/noahheck/E_PDOStatement

ВІДМОВЛЕННЯ :
Очевидно, як я вже згадував, я написав це розширення. Оскільки це було розроблено за допомогою багатьох ниток тут, я хотів опублікувати тут своє рішення на випадок, якщо хтось інший натрапив на ці теми, як і я.


Дякую, що поділились. Немає жодних пропозицій, оскільки занадто довга відповідь із занадто маленьким кодом
T30,

1

Згадане властивість $ queryString, ймовірно, поверне лише переданий запит, без параметрів, замінених на їх значення. У .Net, у мене вловлююча частина мого виконавця запитів виконує просту пошук заміни параметрів на їх значення, які були надані, щоб журнал помилок міг відображати фактичні значення, які використовувались для запиту. Ви повинні мати можливість перерахувати параметри в PHP та замінити параметри на присвоєне їм значення.


1

Можна використовувати sprintf(str_replace('?', '"%s"', $sql), ...$params);

Ось приклад:

function mysqli_prepared_query($link, $sql, $types='', $params=array()) {
    echo sprintf(str_replace('?', '"%s"', $sql), ...$params);
    //prepare, bind, execute
}

$link = new mysqli($server, $dbusername, $dbpassword, $database);
$sql = "SELECT firstname, lastname FROM users WHERE userage >= ? AND favecolor = ?";
$types = "is"; //integer and string
$params = array(20, "Brown");

if(!$qry = mysqli_prepared_query($link, $sql, $types, $params)){
    echo "Failed";
} else {
    echo "Success";
}

Зверніть увагу, це працює лише для PHP> = 5.6


0

Я знаю, що це питання трохи старе, але я використовую цей код ще з давнього часу (я використовував відповідь від @ chris-go), і тепер цей код застарів із PHP 7.2

Я опублікую оновлену версію цього коду (за основний код належать @bigwebguy , @mike та @ chris-go , всі вони відповідають на це питання):

/**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public function interpolateQuery($query, $params) {
    $keys = array();
    $values = $params;

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }

        if (is_array($value))
            $values[$key] = implode(',', $value);

        if (is_null($value))
            $values[$key] = 'NULL';
    }
    // Walk the array to see if we can add single-quotes to strings
    array_walk($values, function(&$v, $k) { if (!is_numeric($v) && $v != "NULL") $v = "\'" . $v . "\'"; });

    $query = preg_replace($keys, $values, $query, 1, $count);

    return $query;
}

Зверніть увагу, що зміни в коді є функцією array_walk (), замінюючи create_function анонімною функцією. Це робить цей хороший фрагмент коду функціональним та сумісним із PHP 7.2 (і сподіваємось, що і майбутні версії).


-1

Дещо пов’язане ... якщо ви просто намагаєтеся очистити певну змінну, ви можете використовувати PDO :: quota . Наприклад, для пошуку кількох часткових умов LIKE, якщо ви застрягли з обмеженою рамкою, як-от CakePHP:

$pdo = $this->getDataSource()->getConnection();
$results = $this->find('all', array(
    'conditions' => array(
        'Model.name LIKE ' . $pdo->quote("%{$keyword1}%"),
        'Model.name LIKE ' . $pdo->quote("%{$keyword2}%"),
    ),
);

-1

Відповідь Майка працює добре, поки ви не використовуєте значення прив'язки "повторне використання".
Наприклад:

SELECT * FROM `an_modules` AS `m` LEFT JOIN `an_module_sites` AS `ms` ON m.module_id = ms.module_id WHERE 1 AND `module_enable` = :module_enable AND `site_id` = :site_id AND (`module_system_name` LIKE :search OR `module_version` LIKE :search)

Відповідь Майка може замінити лише перше: пошук, але не друге.
Отже, я переписав його відповідь для роботи з декількома параметрами, які можна повторно використовувати належним чином.

public function interpolateQuery($query, $params) {
    $keys = array();
    $values = $params;
    $values_limit = [];

    $words_repeated = array_count_values(str_word_count($query, 1, ':_'));

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
            $values_limit[$key] = (isset($words_repeated[':'.$key]) ? intval($words_repeated[':'.$key]) : 1);
        } else {
            $keys[] = '/[?]/';
            $values_limit = [];
        }

        if (is_string($value))
            $values[$key] = "'" . $value . "'";

        if (is_array($value))
            $values[$key] = "'" . implode("','", $value) . "'";

        if (is_null($value))
            $values[$key] = 'NULL';
    }

    if (is_array($values)) {
        foreach ($values as $key => $val) {
            if (isset($values_limit[$key])) {
                $query = preg_replace(['/:'.$key.'/'], [$val], $query, $values_limit[$key], $count);
            } else {
                $query = preg_replace(['/:'.$key.'/'], [$val], $query, 1, $count);
            }
        }
        unset($key, $val);
    } else {
        $query = preg_replace($keys, $values, $query, 1, $count);
    }
    unset($keys, $values, $values_limit, $words_repeated);

    return $query;
}

-1

preg_replace не працював для мене, і коли прив'язка_ перевищувала 9, зв'язування_1 та прив’язка_10 були замінені на str_replace (залишивши 0 позаду), тому я зробив заміни назад:

public function interpolateQuery($query, $params) {
$keys = array();
    $length = count($params)-1;
    for ($i = $length; $i >=0; $i--) {
            $query  = str_replace(':binding_'.(string)$i, '\''.$params[$i]['val'].'\'', $query);
           }
        // $query  = str_replace('SQL_CALC_FOUND_ROWS', '', $query, $count);
        return $query;

}

Сподіваюся, хтось вважає це корисним.


-1

Мені потрібно ввійти повний рядок запиту після прив'язки парам, так що це частина в моєму коді. Сподіваюся, корисно для всіх капелюх має те саме питання.

/**
 * 
 * @param string $str
 * @return string
 */
public function quote($str) {
    if (!is_array($str)) {
        return $this->pdo->quote($str);
    } else {
        $str = implode(',', array_map(function($v) {
                    return $this->quote($v);
                }, $str));

        if (empty($str)) {
            return 'NULL';
        }

        return $str;
    }
}

/**
 * 
 * @param string $query
 * @param array $params
 * @return string
 * @throws Exception
 */
public function interpolateQuery($query, $params) {
    $ps = preg_split("/'/is", $query);
    $pieces = [];
    $prev = null;
    foreach ($ps as $p) {
        $lastChar = substr($p, strlen($p) - 1);

        if ($lastChar != "\\") {
            if ($prev === null) {
                $pieces[] = $p;
            } else {
                $pieces[] = $prev . "'" . $p;
                $prev = null;
            }
        } else {
            $prev .= ($prev === null ? '' : "'") . $p;
        }
    }

    $arr = [];
    $indexQuestionMark = -1;
    $matches = [];

    for ($i = 0; $i < count($pieces); $i++) {
        if ($i % 2 !== 0) {
            $arr[] = "'" . $pieces[$i] . "'";
        } else {
            $st = '';
            $s = $pieces[$i];
            while (!empty($s)) {
                if (preg_match("/(\?|:[A-Z0-9_\-]+)/is", $s, $matches, PREG_OFFSET_CAPTURE)) {
                    $index = $matches[0][1];
                    $st .= substr($s, 0, $index);
                    $key = $matches[0][0];
                    $s = substr($s, $index + strlen($key));

                    if ($key == '?') {
                        $indexQuestionMark++;
                        if (array_key_exists($indexQuestionMark, $params)) {
                            $st .= $this->quote($params[$indexQuestionMark]);
                        } else {
                            throw new Exception('Wrong params in query at ' . $index);
                        }
                    } else {
                        if (array_key_exists($key, $params)) {
                            $st .= $this->quote($params[$key]);
                        } else {
                            throw new Exception('Wrong params in query with key ' . $key);
                        }
                    }
                } else {
                    $st .= $s;
                    $s = null;
                }
            }
            $arr[] = $st;
        }
    }

    return implode('', $arr);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.