PDO tarafından hazırlanmış ifadelerden ham SQL sorgu dizesi alma


130

Hazırlanmış bir ifadede PDOStatement :: execute () çağrılırken çalıştırılan ham SQL dizgesini almanın bir yolu var mı? Hata ayıklama amacıyla bu son derece yararlı olacaktır.



1
Tek satırlık pdo-debug işlevini kontrol edin .
Sliq

Bulduğum en temiz yol E_PDOStatement kitaplığı. Sadece yaparsın $stmt = $pdo->prepare($query); /* ... */ echo $stmt->fullQuery;. PDOStatement sınıfını genişleterek çalışır , dolayısıyla PDO API'nin izin verdiği kadar zariftir.
ComFreek

Yanıtlar:


110

Son SQL sorgusunu, içine eklenen parametre değerleriyle birlikte istediğinizi varsayıyorum. Bunun hata ayıklama için yararlı olacağını anlıyorum, ancak hazırlanan ifadelerin çalışma şekli bu değildir. Parametreler, istemci tarafında hazırlanmış bir ifadeyle birleştirilmez, bu nedenle PDO'nun hiçbir zaman parametreleriyle birlikte sorgu dizesine erişimi olmamalıdır.

Prepar () işlemini yaptığınızda SQL deyimi veritabanı sunucusuna gönderilir ve execute () işlemini gerçekleştirdiğinizde parametreler ayrı olarak gönderilir. MySQL'in genel sorgu günlüğü, siz () çalıştırdıktan sonra enterpolasyonlu değerlerle son SQL'i gösterir. Aşağıda genel sorgu günlüğümden bir alıntı var. Sorguları mysql CLI'den çalıştırdım, PDO'dan değil, ama prensip aynı.

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

Ayrıca PDO özniteliğini PDO :: ATTR_EMULATE_PREPARES olarak ayarlarsanız, istediğinizi elde edebilirsiniz. Bu modda, PDO parametreleri SQL sorgusuna ekler ve () komutunu çalıştırdığınızda tüm sorguyu gönderir. Bu gerçek hazırlanmış bir sorgu değil. Execute () işleminden önce değişkenleri SQL dizesine enterpolasyon yaparak hazırlanmış sorguların faydalarından kaçınacaksınız.


@Afilina'dan yeniden yorum:

Hayır, metinsel SQL sorgusu edilir değil yürütme sırasında parametreleri ile birleştirdi. Yani PDO'nun size göstereceği hiçbir şey yok.

Dahili olarak, PDO :: ATTR_EMULATE_PREPARES kullanırsanız, PDO, hazırlayıp çalıştırmadan önce SQL sorgusunun bir kopyasını oluşturur ve parametre değerlerini buna enterpolasyonlar. Ancak PDO, bu değiştirilmiş SQL sorgusunu açığa çıkarmaz.

PDOStatement nesnesi $ queryString özelliğine sahiptir, ancak bu yalnızca PDOStatement yapıcısında ayarlanır ve sorgu parametrelerle yeniden yazıldığında güncellenmez.

PDO'nun yeniden yazılan sorguyu ifşa etmesini istemesi makul bir özellik isteği olacaktır. Ancak bu bile PDO :: ATTR_EMULATE_PREPARES kullanmadığınız sürece size "tam" sorguyu vermez.

Bu nedenle, MySQL sunucusunun genel sorgu günlüğünü kullanmanın yukarıdaki geçici çözümünü gösteriyorum, çünkü bu durumda parametre yer tutuculara sahip hazırlanmış bir sorgu bile, parametre değerleri sorgu dizesine doldurularak sunucuda yeniden yazılır. Ancak bu, sorgu yürütme sırasında değil, yalnızca günlük kaydı sırasında yapılır.


10
PDO :: ATTR_EMULATE_PREPARES TRUE olarak ayarlandığında delik sorgusunu nasıl elde edersiniz?
Yasen Zhelev

2
@Yasen Zhelev: PDO hazırlığı taklit ediyorsa, sorguyu hazırlamadan önce parametre değerlerini sorguya ekleyecektir. Dolayısıyla MySQL, sorgunun sürümünü parametre yer tutucularla asla görmez. MySQL yalnızca tam sorguyu günlüğe kaydeder.
Bill Karwin

2
@ Bill: 'Parametreler, istemci tarafında hazırlanmış bir ifade ile birleştirilmez' - bekleyin - ama sunucu tarafında birleştiriliyorlar mı? Veya mysql değerleri DB'ye nasıl ekler?
Stann

1
@afilina, hayır, yapamazsın. Yukarıdaki açıklamama bakın.
Bill Karwin

3
Vay canına, olumsuz oy mu? Lütfen haberciye ateş etmeyin. Sadece nasıl çalıştığını anlatıyorum.
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
neden sadece kullanmayalım strtr(): daha hızlı, daha basit, aynı sonuçlar. strtr($query, $params);
Tony Chiboucas

Bunun kullanımı nedir?

Sadece uğramak ve teşekkür etmek istedim, bunun için ekstra bir sınıfın dışındaydı ve şimdi bunun lehine kaldırdım, küçük ve parlak :). Bir uygulamanın her sayfada yaptığı tüm sorguları günlüğe
kaydederek hata ayıklamak

Bu işlevi gördüm ve beni çok mutlu etti, yine de anlamadığım bir şey, neden $keya stringve değil olup olmadığını kontrol ediyorsunuz $value? Bir şey mi kaçırıyorum? Bunu sormamın nedeni bu çıktı yüzünden ikinci parametrenin bir dizge olarak görülmemesi:string(115) "INSERT INTO tokens (token_type, token_hash, user_id) VALUES ('resetpassword', hzFs5RLMpKwTeShTjP9AkTA2jtxXls86, 1);"
Kerwin Sneijders

1
Bu iyi bir başlangıçtır, ancak bir $ param değerinin kendisi bir soru işareti ("?") İçeriyorsa başarısız olur.
chickenchilli

32

Yöntemi, WHERE IN (?) Gibi ifadeler için dizilerin işleme çıktılarını içerecek şekilde değiştirdim.

GÜNCELLEME: NULL değeri için kontrol eklendi ve $ parametreleri çoğaltıldı, böylece gerçek $ param değerleri değiştirilmez.

Harika iş büyük adam ve teşekkürler!

/**
 * 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
Bunun $values = $params;yerine yapman gerektiğini düşünüyorum $values = array().
test

Burada gözden kaçan bir diğer küçük parça ise dizelerdir. is_arrayif (is_string($value)) $values[$key] = "'" . $value . "'";
Bunları

Bu, preg_replace'de yalnızca bir kez sınırlı bağlanma değeridir. bu satırı $values = $params; $values_limit = []; $words_repeated = array_count_values(str_word_count($sql, 1, ':_')); önce bunu içine ekledikten sonra ekleyin, eğer foreach ise $values_limit[$key] = (isset($words_repeated[':'.$key]) ? intval($words_repeated[':'.$key]) : 1);ve bu ilk önce foreach'ta $values_limit = [];foreach döngüsünde $ değerler tekrar kullanınisset($values_limit[$key])
vee

örneğin döngü $ değerleri. 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

Muhtemelen biraz geç ama şimdi var PDOStatement::debugDumpParams

Hazırlanmış bir ifadenin içerdiği bilgileri doğrudan çıktıya döker. Kullanılan SQL sorgusunu, kullanılan parametrelerin sayısını (Parametreler), parametrelerin listesini, adları, tamsayı olarak tipi (paramtype), anahtar adı veya konumu ve sorgudaki konumu (eğer bu PDO sürücüsü tarafından desteklenir, aksi takdirde -1 olacaktır).

Resmi php belgelerinde daha fazlasını bulabilirsiniz

Misal:

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

?>


ve daha iyi okunabilirlik için:echo '<pre>'; $sth->debugDumpParams(); echo '</pre>';
SandroMarques

10

Çözüm, sorguya gönüllü olarak bir hata eklemek ve hatanın mesajını yazdırmaktır:

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

Standart çıktı:

SQLSTATE [42000]: Sözdizimi hatası veya erişim ihlali: [...] 1. satırda 'ELECT * FROM Person WHERE WHERE yaş = 18' yakınında

Sorgunun yalnızca ilk 80 karakterini yazdırdığına dikkat etmek önemlidir.


Bunun neden reddedildiğini bilmiyorum. Basit ve işe yarıyor. Hızlı çalışır. Günlüğü açıp, günlükte doğru satırı aramadan, ardından günlüğü devre dışı bırakıp ardından günlük dosyalarını temizlemekten çok daha hızlı.
Bojan Hrnkas

@BojanHrnkas hata örneğinin uzunluğu çok sınırlıdır. Bu kadar basit bir sorgu için, bir yer tutucuyu bir değişkenle sadece manuel olarak değiştirmek daha kolaydır. Ve bu yöntem yalnızca öykünmeyi etkinleştirirseniz çalışır.
Sizin Common Sense

9

Mike tarafından koda biraz daha eklendi - tek tırnak eklemek için değerleri yürüyün

/**
 * 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
Çok yararlı bir şekilde, PDOStatement sınıfının bindParam işlevini geçersiz kılmak ve değerin PDO: PARAMS değerleriyle bir dize veya tamsayı olup olmadığını doğrulamak için bazı değişiklikler yaptım .
Sergio Flores

1
bunu nerede görebiliriz?
Mawg, Monica'nın

8

PDOStatement, $ queryString genel özelliğine sahiptir. İstediğin şey olmalı.

PDOStatement'ın belgelenmemiş bir debugDumpParams () yöntemine sahip olduğunu fark ettim, buna da bakmak isteyebilirsiniz.



Hayır! $ queryString, dahil edilen param değerlerini göstermez.
Andreas

5

PDOStatement sınıfını, sınırlı değişkenleri yakalamak ve daha sonra kullanmak üzere saklamak için genişletebilirsiniz. Daha sonra biri değişken temizleme için (debugBindedVariables) ve diğeri sorguyu bu değişkenlerle yazdırmak için (debugQuery) 2 yöntem eklenebilir:

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

Ve sonra bu miras alınan sınıfı, amaçlarda hata ayıklamak için kullanabilirsiniz.

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

Sonuçlanan

Kullanıcılardan kullanıcı seçin WHERE user = 'user_test'

Dizi ([: test] => user_test)


4

Kendi ihtiyaçlarım için bu durumu araştırmak için çok zaman harcadım. Bu ve diğer birkaç SO dizisi bana çok yardımcı oldu, bu yüzden bulduğum şeyi paylaşmak istedim.

Enterpolasyonlu sorgu dizesine erişim, sorun giderme sırasında önemli bir avantaj olsa da, yalnızca belirli sorguların günlüğünü tutabilmek istedik (bu nedenle, bu amaçla veritabanı günlüklerini kullanmak ideal değildi). Ayrıca, herhangi bir zamanda tabloların durumunu yeniden oluşturmak için günlükleri kullanabilmek istedik, bu nedenle, enterpolasyonlu dizelerin düzgün şekilde kaçtığından emin olmamız gerekiyordu. Son olarak, bu işlevselliği mümkün olduğunca az yeniden yazmak zorunda olan tüm kod tabanımıza genişletmek istedik (son tarihler, pazarlama vb. Nasıl olduğunu biliyorsunuz).

Benim çözümüm, parametreleştirilmiş değerleri (veya referansları) önbelleğe almak için varsayılan PDOStatement nesnesinin işlevselliğini genişletmek ve ifade yürütüldüğünde, parametreler sorguya geri enjekte edildiklerinde uygun şekilde kaçmak için PDO nesnesinin işlevselliğini kullanmaktı. dize. Daha sonra, ifade nesnesinin yöntemini yürütmek ve o sırada yürütülen gerçek sorguyu günlüğe kaydetmek için bağlayabiliriz ( veya en azından bir çoğaltmaya mümkün olduğunca sadık kalırız) .

Dediğim gibi, bu işlevselliği eklemek için tüm kod tabanını değiştirmek istemedik, bu nedenle PDOStatement nesnesinin varsayılan bindParam()ve bindValue()yöntemlerinin üzerine yazıyoruz, bağlı verileri önbelleğe alıyoruz, sonra çağrı parent::bindParam()veya parent ::bindValue() . Bu, mevcut kod tabanımızın normal şekilde çalışmaya devam etmesine izin verdi.

Son olarak, execute()yöntem çağrıldığında, enterpolasyonumuzu gerçekleştiririz ve ortaya çıkan dizeyi yeni bir özellik olarak sağlarız E_PDOStatement->fullQuery. Bu, sorguyu görüntülemek için çıktı olabilir veya örneğin bir günlük dosyasına yazılabilir.

Uzantı, kurulum ve yapılandırma talimatlarıyla birlikte github'da mevcuttur:

https://github.com/noahheck/E_PDOStatement

SORUMLULUK REDDİ :
Açıkçası, bahsettiğim gibi, bu uzantıyı yazdım. Buradaki birçok iş parçacığının yardımıyla geliştirildiğinden, benim yaptığım gibi başka birinin bu konularla karşılaşması durumunda çözümümü buraya göndermek istedim.


Paylaşım için teşekkürler. Olumlu oy yok çünkü çok az kodla çok uzun yanıt
T30

1

Bahsedilen $ queryString özelliği, büyük olasılıkla, parametreler değerleri ile değiştirilmeden yalnızca iletilen sorguyu döndürecektir. .Net'te, sorgu yürütücümün catch kısmına, parametreler üzerinde sağlanan değerlerle basit bir arama değiştirmesini sağlıyorum, böylece hata günlüğü sorgu için kullanılan gerçek değerleri gösterebilir. PHP'deki parametreleri numaralandırabilmeli ve parametreleri atanmış değerleriyle değiştirebilmelisiniz.


1

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

İşte bir örnek:

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

Bunun yalnızca PHP> = 5.6 için çalıştığını unutmayın.


0

Bu sorunun biraz eski olduğunu biliyorum, ancak bu kodu çok zaman önce kullanıyorum (@ chris-go'dan yanıt kullandım) ve şimdi bu kod PHP 7.2'de kullanılmıyor

Bu kodun güncellenmiş bir sürümünü yayınlayacağım (Ana koda ilişkin kredi @bigwebguy , @mike ve @ chris- go'dan alınmıştır , hepsi bu sorunun yanıtlarıdır):

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

Koddaki değişikliğin array_walk () işlevinde olduğuna ve create_function yerine anonim bir işlev olduğuna dikkat edin. Bu, bu iyi kod parçasını PHP 7.2 ile işlevsel ve uyumlu hale getirir (ve gelecekteki sürümleri de umarız).


-1

Biraz ilgili ... eğer sadece belirli bir değişkeni sterilize etmeye çalışıyorsanız, PDO :: quote kullanabilirsiniz . Örneğin, CakePHP gibi sınırlı bir çerçeveye sıkışmışsanız birden fazla kısmi LIKE koşulu aramak için:

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

-1

Mike'ın cevabı , siz "yeniden kullan" bağlama değerini kullanana kadar iyi çalışıyor.
Örneğin:

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)

Mike'ın cevabı yalnızca birincinin yerini alabilir: arama, ikinciyi değil.
Bu yüzden, cevabını doğru şekilde yeniden kullanılabilen birden çok parametre ile çalışmak için yeniden yazıyorum.

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 benim için işe yaramadı ve bağlama_ 9'un üzerinde olduğunda, bağlama_1 ve bağlama_10, str_replace ile değiştirildi (0'ı geride bırakarak), bu yüzden değişiklikleri geriye doğru yaptım:

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;

}

Umarım birisi onu yararlı bulur.


-1

Bind parametresinden sonra tam sorgu dizesini günlüğe kaydetmem gerekiyor, böylece bu kodumdaki bir parça. Umarım aynı konuya sahip şapka herkes için faydalıdır.

/**
 * 
 * @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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.