Ottenere una stringa di query SQL non elaborata dalle istruzioni preparate DOP


130

C'è un modo per ottenere la stringa SQL non elaborata quando si chiama PDOStatement :: execute () su un'istruzione preparata? Ai fini del debug questo sarebbe estremamente utile.



1
Controlla la funzione di una riga pdo-debug .
Sliq,

Il modo più pulito che ho trovato è la libreria E_PDOStatement . Lo fai e basta $stmt = $pdo->prepare($query); /* ... */ echo $stmt->fullQuery;. Funziona estendendo la classe PDOStatement , quindi è elegante come l'API PDO consente.
ComFreek

Risposte:


110

Presumo tu intenda che vuoi la query SQL finale, con i valori dei parametri interpolati in essa. Capisco che questo sarebbe utile per il debug, ma non è il modo in cui funzionano le istruzioni preparate. I parametri non sono combinati con un'istruzione preparata sul lato client, quindi PDO non dovrebbe mai avere accesso alla stringa di query combinata con i suoi parametri.

L'istruzione SQL viene inviata al server di database quando si prepara () e i parametri vengono inviati separatamente quando si esegue execute (). Il log delle query generali di MySQL mostra l'SQL finale con valori interpolati dopo aver eseguito (). Di seguito è riportato un estratto dal mio registro generale delle query. Ho eseguito le query dall'interfaccia della riga di comando mysql, non da DOP, ma il principio è lo stesso.

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

Puoi anche ottenere ciò che desideri se imposti l'attributo DOP DOP :: ATTR_EMULATE_PREPARES. In questa modalità, PDO interpola i parametri nella query SQL e invia l'intera query quando si esegue (). Questa non è una vera query preparata. Eviterai i vantaggi delle query preparate interpolando le variabili nella stringa SQL prima di execute ().


Re commento da @afilina:

No, la query SQL testuale non è combinata con i parametri durante l'esecuzione. Quindi non c'è niente che PDO ti mostri.

Internamente, se si utilizza PDO :: ATTR_EMULATE_PREPARES, PDO crea una copia della query SQL e interpola i valori dei parametri in essa prima di eseguire la preparazione ed esecuzione. Ma PDO non espone questa query SQL modificata.

L'oggetto PDOStatement ha una proprietà $ queryString, ma questa è impostata solo nel costruttore per PDOStatement e non viene aggiornata quando la query viene riscritta con i parametri.

Sarebbe una ragionevole richiesta di funzionalità per PDO chiedere loro di esporre la query riscritta. Ma anche questo non ti darebbe la query "completa" se non usi PDO :: ATTR_EMULATE_PREPARES.

Questo è il motivo per cui mostro la soluzione sopra descritta relativa all'utilizzo del registro delle query generale del server MySQL, poiché in questo caso anche una query preparata con segnaposto dei parametri viene riscritta sul server, con i valori dei parametri riempiti nuovamente nella stringa di query. Ma questo viene fatto solo durante la registrazione, non durante l'esecuzione della query.


10
E come si ottiene la query sul foro quando PDO :: ATTR_EMULATE_PREPARES è impostato su TRUE?
Yasen Zhelev,

2
@Yasen Zhelev: Se il PDO emula i preparativi, interpolerà i valori dei parametri nella query prima di preparare la query. Quindi MySQL non vede mai la versione della query con segnaposto dei parametri. MySQL registra solo la query completa.
Bill Karwin,

2
@ Bill: "I parametri non sono combinati con un'istruzione preparata sul lato client" - aspetta - ma combinati sul lato server? O come mysql inserisce valori nel DB?
Stann,

1
@afilina, no, non puoi. Vedi la mia spiegazione sopra.
Bill Karwin,

3
Wow, un downvote? Per favore, non sparare al messaggero. Sto solo descrivendo come funziona.
Bill Karwin,

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
perché non usare solo strtr(): più veloce, più semplice, stessi risultati. strtr($query, $params);
Tony Chiboucas,

A cosa serve questo?

Volevo solo fermarmi e ringraziare anche, era fuori da un'intera classe extra per questo che ora ho rimosso a favore di questo perché è piccolo e brillante :). Così dannatamente utile per dover eseguire il debug di tutte le query che un'applicazione sta eseguendo su ogni pagina registrandole: D
NaughtySquid

Ho visto questa funzione e mi ha fatto molto piacere, anche se, qualcosa che non capisco, perché controlli $keyper essere un stringe no $value? Mi sto perdendo qualcosa? Il motivo per cui lo chiedo è a causa di questo output, il secondo parametro non è visto come una stringa:string(115) "INSERT INTO tokens (token_type, token_hash, user_id) VALUES ('resetpassword', hzFs5RLMpKwTeShTjP9AkTA2jtxXls86, 1);"
Kerwin Sneijders

1
Questo è un buon inizio, ma fallisce se il valore di $ param stesso include un punto interrogativo ("?").
Chickenchilli,

32

Ho modificato il metodo per includere la gestione dell'output di array per istruzioni come WHERE IN (?).

AGGIORNAMENTO: appena aggiunto controllare il valore NULL e duplicati $ params in modo che i valori effettivi $ param non vengano modificati.

Ottimo lavoro bigwebguy e grazie!

/**
 * 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
Penso che devi fare $values = $params;invece di $values = array().
test del

Un altro piccolo pezzo che manca qui sono le stringhe. Per catturarli, metti questo sopra il is_arraysegno di spunta:if (is_string($value)) $values[$key] = "'" . $value . "'";
treeface

Questo valore di bind è limitato a una sola volta in preg_replace. aggiungi questa riga dopo $values = $params; $values_limit = []; $words_repeated = array_count_values(str_word_count($sql, 1, ':_')); aggiungi prima questa dentro in foreach $values_limit[$key] = (isset($words_repeated[':'.$key]) ? intval($words_repeated[':'.$key]) : 1);e questa prima in foreach $values_limit = [];usa foreach loop $ valori di nuovo in preg_replace conisset($values_limit[$key])
v

ad esempio loop $ valori. 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); }
V,

12

Probabilmente un po 'in ritardo, ma ora c'è PDOStatement::debugDumpParams

Scarica le informazioni contenute da un'istruzione preparata direttamente sull'output. Fornirà la query SQL in uso, il numero di parametri utilizzati (Params), l'elenco dei parametri, con il loro nome, tipo (paramtype) come numero intero, nome o posizione della chiave e posizione nella query (se questo è supportato dal driver PDO, altrimenti sarà -1).

Puoi trovare ulteriori informazioni sui documenti php ufficiali

Esempio:

<?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();

?>


e per una migliore leggibilità:echo '<pre>'; $sth->debugDumpParams(); echo '</pre>';
SandroMarques,

10

Una soluzione è inserire volontariamente un errore nella query e stampare il messaggio di errore:

//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();
}

Uscita standard:

SQLSTATE [42000]: errore di sintassi o violazione di accesso: [...] vicino a "ELECT * FROM Person WHERE age = 18" alla riga 1

È importante notare che stampa solo i primi 80 caratteri della query.


Non so perché questo sia stato sottoposto a downgrade. È semplice e funziona. Funziona velocemente Molto più veloce che accendere il log, cercare la riga giusta nel log, quindi disabilitare il log, quindi ripulire i file di log.
Bojan Hrnkas,

@BojanHrnkas la lunghezza dell'esempio di errore è molto limitata. Per una query così semplice è più semplice sostituire un segnaposto con una variabile solo manualmente. E questo metodo funziona solo se si abilita l'emulazione.
Il tuo buon senso

9

Aggiunto un po 'di più al codice di Mike - cammina i valori per aggiungere virgolette singole

/**
 * 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
Molto utilmente, ho fatto alcune modifiche per sovrascrivere il BindParam funzione della PDOStatement classe e confermare se il valore è una stringa o un numero intero con il PDO: PARAMS valori.
Sergio Flores,

dove possiamo vederlo?
Mawg dice di reintegrare Monica il


5

È possibile estendere la classe PDOStatement per acquisire le variabili limitate e memorizzarle per un uso successivo. Quindi possono essere aggiunti 2 metodi, uno per la sanificazione delle variabili (debugBindedVariables) e un altro per stampare la query con quelle variabili (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);
  }
}

E quindi è possibile utilizzare questa classe ereditata per il debug degli scopi.

$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());

Con il risultato di

SELEZIONA utente DA utenti DOVE utente = 'user_test'

Array ([: test] => user_test)


4

Ho trascorso molto tempo a ricercare questa situazione per le mie esigenze. Questo e molti altri thread SO mi hanno aiutato moltissimo, quindi volevo condividere ciò che mi è venuto in mente.

Pur avendo accesso alla stringa di query interpolata è un vantaggio significativo durante la risoluzione dei problemi, volevamo essere in grado di mantenere un registro di solo alcune query (pertanto, utilizzare i registri del database per questo scopo non era l'ideale). Volevamo anche essere in grado di utilizzare i log per ricreare la condizione delle tabelle in qualsiasi momento, quindi, dovevamo assicurarci che le stringhe interpolate fossero sfuggite correttamente. Infine, volevamo estendere questa funzionalità a tutta la nostra base di codice, riscrivendone il meno possibile (scadenze, marketing e così; sai com'è).

La mia soluzione era quella di estendere la funzionalità dell'oggetto PDOStatement predefinito per memorizzare nella cache i valori (o riferimenti) parametrizzati e, quando viene eseguita l'istruzione, utilizzare la funzionalità dell'oggetto PDO per sfuggire correttamente ai parametri quando vengono reimmessi nella query corda. Potremmo quindi collegarci per eseguire il metodo dell'oggetto istruzione e registrare la query effettiva eseguita in quel momento ( o almeno il più fedele possibile di una riproduzione) .

Come ho detto, non volevamo modificare l'intera base di codice per aggiungere questa funzionalità, quindi sovrascriviamo i metodi predefiniti bindParam()e i bindValue()metodi dell'oggetto PDOStatement, eseguiamo la memorizzazione nella cache dei dati associati, quindi chiamiamo parent::bindParam()o parent :: bindValue(). Ciò ha consentito alla nostra base di codice esistente di continuare a funzionare normalmente.

Alla fine, quando execute()viene chiamato il metodo, eseguiamo la nostra interpolazione e forniamo la stringa risultante come nuova proprietà E_PDOStatement->fullQuery. Questo può essere emesso per visualizzare la query o, ad esempio, scritto in un file di registro.

L'estensione, insieme alle istruzioni di installazione e configurazione, sono disponibili su github:

https://github.com/noahheck/E_PDOStatement

DISCLAIMER :
Ovviamente, come ho già detto, ho scritto questa estensione. Poiché è stato sviluppato con l'aiuto di molti thread qui, volevo pubblicare qui la mia soluzione nel caso in cui qualcuno incontrasse questi thread, proprio come ho fatto io.


Grazie per la condivisione. Nessun voto perché risposta troppo lunga con troppo poco codice
T30

1

La proprietà $ queryString menzionata probabilmente restituirà solo la query passata, senza i parametri sostituiti con i loro valori. In .Net, ho la parte catch del mio programma di esecuzione di query fare una semplice sostituzione di ricerca sui parametri con i loro valori che è stato fornito in modo che il registro degli errori possa mostrare i valori effettivi utilizzati per la query. Dovresti essere in grado di enumerare i parametri in PHP e sostituirli con il loro valore assegnato.


1

Puoi usare sprintf(str_replace('?', '"%s"', $sql), ...$params);

Ecco un esempio:

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";
}

Nota che funziona solo per PHP> = 5.6


0

So che questa domanda è un po 'vecchia, ma sto usando questo codice da molto tempo fa (ho usato la risposta di @ chris-go) e ora questi codici sono obsoleti con PHP 7.2

Pubblicherò una versione aggiornata di questo codice (i crediti per il codice principale sono di @bigwebguy , @mike e @ chris-go , tutti risposte a questa domanda):

/**
 * 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;
}

Nota che le modifiche al codice sono sulla funzione array_walk (), che sostituisce create_function con una funzione anonima. Questo rende questo buon pezzo di codice funzionale e compatibile con PHP 7.2 (e spero anche le versioni future).


-1

In qualche modo correlato ... se stai solo cercando di disinfettare una particolare variabile puoi usare PDO :: quote . Ad esempio, per cercare più condizioni LIKE parziali se sei bloccato con un framework limitato come 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

La risposta di Mike funziona bene fino a quando non si utilizza il valore di bind "riutilizzo".
Per esempio:

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)

La risposta di Mike può sostituire solo la prima: cerca ma non la seconda.
Quindi, riscrivo la sua risposta per lavorare con più parametri che possono essere riutilizzati correttamente.

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 non ha funzionato per me e quando binding_ era superiore a 9, binding_1 e binding_10 sono stati sostituiti con str_replace (lasciando lo 0 indietro), quindi ho effettuato le sostituzioni al contrario:

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;

}

Spero che qualcuno lo trovi utile.


-1

Ho bisogno di registrare la stringa di query completa dopo il parametro bind, quindi questo è un pezzo nel mio codice. Spero che sia utile per tutti coloro che hanno lo stesso problema.

/**
 * 
 * @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);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.