PDO 준비 명령문에서 원시 SQL 쿼리 문자열 가져 오기


130

준비된 명령문에서 PDOStatement :: execute ()를 호출 할 때 원시 SQL 문자열을 실행하는 방법이 있습니까? 디버깅 목적으로 매우 유용합니다.



1
한 줄 함수 pdo-debug를 확인하십시오 .
Sliq

내가 찾은 가장 깨끗한 방법은 E_PDOStatement 라이브러리입니다. 당신은 그냥 $stmt = $pdo->prepare($query); /* ... */ echo $stmt->fullQuery;합니다. PDOStatement 클래스확장하여 작동 하므로 PDO API가 허용하는 한 우아합니다.
ComFreek

답변:


110

매개 변수 값을 보간하여 최종 SQL 쿼리를 원한다고 가정합니다. 디버깅에 유용하지만 준비된 명령문이 작동하는 방식은 아니라는 것을 알고 있습니다. 매개 변수는 클라이언트 측에서 준비된 명령문과 결합되지 않으므로 PDO는 해당 매개 변수와 결합 된 쿼리 문자열에 액세스 할 수 없습니다.

SQL 문은 준비 ()를 수행 할 때 데이터베이스 서버로 전송되고 매개 변수는 execute ()를 수행 할 때 별도로 전송됩니다. MySQL의 일반 쿼리 로그에는 execute () 후에 보간 된 값과 함께 최종 SQL이 표시됩니다. 아래는 일반적인 쿼리 로그에서 발췌 한 것입니다. PDO가 아닌 mysql CLI에서 쿼리를 실행했지만 원칙은 동일합니다.

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 쿼리에 보간하고 실행할 때 전체 쿼리를 보냅니다. 이것은 실제 준비된 쿼리가 아닙니다. execute () 전에 변수를 SQL 문자열에 보간하여 준비된 쿼리의 이점을 피할 수 있습니다.


@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로 설정되면 어떻게 구멍 쿼리를 얻습니까?
Yasen Zhelev

2
@Yasen Zhelev : PDO가 준비를 에뮬레이션하는 경우 쿼리를 준비하기 전에 매개 변수 값을 쿼리에 보간합니다. 따라서 MySQL은 매개 변수 자리 표시 자와 함께 쿼리 버전을 보지 못합니다. MySQL은 전체 쿼리 만 기록합니다.
Bill Karwin

2
@ Bill : '매개 변수는 클라이언트 측의 준비된 명령문과 결합되지 않습니다'-대기-서버 측에서는 결합됩니까? 또는 mysql은 어떻게 값을 DB에 삽입합니까?
Stann

1
@afilina, 아니, 당신은 할 수 없습니다. 위의 설명을 참조하십시오.
Bill Karwin

3
와우, 공감대? 메신저를 쏘지 마십시오. 나는 그것이 어떻게 작동하는지 설명하고 있습니다.
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
왜 사용하지 말아야합니까 strtr()? 더 빠르고 단순하며 동일한 결과. strtr($query, $params);
Tony Chiboucas

이것의 사용법은 무엇입니까?

그냥 들러서 감사를 드리고 싶었습니다.이 클래스에 대한 전체 추가 수업이 없었습니다. 응용 프로그램이 각 페이지에서 수행하는 모든 쿼리를 로깅하여 디버깅하는 데 유용합니다. D
NaughtySquid

이 기능을보고, 이해가 안 뭔가, 왜 당신은을 확인 않지만 그것은 나를 매우 행복하게 $key을 되 string하지 $value? 뭔가 빠졌습니까? 내가 묻는 이유는이 출력 때문에 두 번째 매개 변수는 문자열로 표시되지 않습니다.string(115) "INSERT INTO tokens (token_type, token_hash, user_id) VALUES ('resetpassword', hzFs5RLMpKwTeShTjP9AkTA2jtxXls86, 1);"
Kerwin Sneijders

1
이것은 좋은 시작이지만 $ param 자체의 값에 물음표 ( "?")가 있으면 실패합니다.
chickenchilli 2016

32

WHERE IN (?)과 같은 명령문에 대한 배열 출력 처리를 포함하도록 메소드를 수정했습니다.

업데이트 : 방금 NULL 값 검사와 $ params 복제를 추가하여 실제 $ param 값이 수정되지 않았습니다.

대단한 일 webwebguy와 감사합니다!

/**
 * 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 . "'";
treeface

preg_replace에서는 바인드 값이 한 번으로 만 제한됩니다. $values = $params; $values_limit = []; $words_repeated = array_count_values(str_word_count($sql, 1, ':_')); foreach 에있는 경우이 라인을 먼저 추가 한 후 foreach에 $values_limit[$key] = (isset($words_repeated[':'.$key]) ? intval($words_repeated[':'.$key]) : 1);있는 다른 $values_limit = [];경우에는 foreach 루프 $ 값을 다시 사용하여 preg_replaceisset($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), 매개 변수 목록, 이름, 유형 (paramtype)을 정수로, 키 이름 또는 위치 및 쿼리 위치 (이 경우 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] : 구문 오류 또는 액세스 위반 : 1 행 에서 'ELECT * FROM Person WHERE age = 18' 근처 [...]

쿼리의 처음 80 자만 인쇄한다는 점에 유의해야합니다.


이것이 왜 다운 보트인지 모르겠습니다. 간단하고 작동합니다. 빨리 작동합니다. 로그를 켜고 로그에서 올바른 줄을 찾은 다음 로그를 비활성화 한 다음 로그 파일을 정리하는 것보다 훨씬 빠릅니다.
Bojan Hrnkas

@BojanHrnkas 오류 샘플의 길이는 매우 제한적입니다. 이러한 간단한 쿼리의 경우 자리 표시자를 수동으로 변수로 바꾸는 것이 더 쉽습니다. 그리고이 방법은 에뮬레이션을 활성화 한 경우에만 작동합니다.
당신의 상식

9

Mike가 코드에 조금 더 추가했습니다. 작은 따옴표를 추가하려면 값을 걸어보세요.

/**
 * 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
매우 유용하게 PDOStatement 클래스 의 bindParam 함수 를 재정의 하고 값이 PDO : PARAMS 값 의 문자열 또는 정수인지 확인 하기 위해 일부 수정을 수행했습니다 .
Sergio Flores

어디서 볼 수 있습니까?
Mawg는 모니카


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

그런 다음 상속 된 클래스를 사용하여 purpouses를 디버깅 할 수 있습니다.

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

를 야기하는

어디에서 사용자를 선택하십시오. user = 'user_test'

배열 ([: test] => user_test)


4

나는 내 자신의 필요를 위해이 상황을 연구하는데 많은 시간을 보냈다. 이것과 다른 몇 가지 SO 스레드가 크게 도움이되었으므로 내가 생각해 낸 것을 공유하고 싶었습니다.

보간 된 쿼리 문자열에 액세스하면 문제를 해결하는 동안 큰 이점을 얻을 수 있지만 특정 쿼리 만 로그를 유지할 수 있기를 원했습니다 (따라서이 목적으로 데이터베이스 로그를 사용하는 것이 이상적이지 않았습니다). 또한 주어진 시간에 로그를 사용하여 테이블의 조건을 재현 할 수 있기를 원했기 때문에 보간 된 문자열이 올바르게 이스케이프되도록해야했습니다. 마지막으로, 우리는이 기능을 전체 코드베이스까지 확장하여 가능한 적은 부분 ​​만 다시 작성해야했습니다 (마감일, 마케팅 등).

내 솔루션은 기본 PDOStatement 객체의 기능을 확장하여 매개 변수가 지정된 값 (또는 참조)을 캐시하고 명령문이 실행될 때 PDO 객체의 기능을 사용하여 매개 변수가 쿼리에 다시 주입 될 때 매개 변수를 올바르게 이스케이프 처리합니다. 끈. 그런 다음 명령문 객체의 메소드를 실행하고 그 시점에 실행 된 실제 쿼리 ( 또는 가능한 한 충실한 재생산)를 기록 할 수 있습니다 .

내가 말했듯이, 우리는이 기능을 추가하기 위해 전체 코드베이스를 수정하고 싶지 않기 때문에 PDOStatement 객체 의 기본 bindParam()bindValue()메소드를 덮어 쓰고 바인딩 된 데이터를 캐싱 한 다음 parent::bindParam()또는 parent :: 를 호출 bindValue()합니다. 이를 통해 기존 코드베이스가 정상적으로 작동합니다.

마지막으로 execute()메소드가 호출되면 보간을 수행하고 결과 문자열을 새로운 속성으로 제공합니다 E_PDOStatement->fullQuery. 조회를 보거나 예를 들어 로그 파일에 기록하기 위해 출력 될 수 있습니다.

확장은 설치 및 구성 지침과 함께 github에서 사용할 수 있습니다.

https://github.com/noahheck/E_PDOStatement

면책 조항 :
분명히 언급 했듯이이 확장을 작성했습니다. 여기에서 많은 스레드의 도움으로 개발되었으므로 다른 사람이 나처럼 스레드를 가로 질러 올 경우를 대비하여 여기에 솔루션을 게시하고 싶었습니다.


공유해 주셔서 감사합니다. 너무 적은 코드로 너무 긴 답변으로 인해 공감 불가
T30

1

언급 된 $ queryString 속성은 매개 변수를 해당 값으로 바꾸지 않고 전달 된 쿼리 만 반환합니다. .Net에서 쿼리 실행 프로그램의 catch 부분은 매개 변수를 제공된 값으로 간단한 검색 바꾸기를 수행하여 오류 로그에 쿼리에 사용 된 실제 값을 표시 할 수 있습니다. 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 :: quote 사용할 수 있습니다 . 예를 들어 CakePHP와 같은 제한된 프레임 워크를 사용하는 경우 여러 부분 LIKE 조건을 검색하려면 다음을 수행하십시오.

$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의 대답 은 "재사용"바인드 값을 사용할 때까지 잘 작동합니다.
예를 들면 다음과 같습니다.

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의 답변은 첫 번째 검색 만 대체 할 수 있지만 두 번째 검색은 대체 할 수 없습니다.
따라서 올바르게 재사용 할 수있는 여러 매개 변수로 작업하기 위해 그의 대답을 다시 씁니다.

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가 작동하지 않았고 binding_이 9를 초과하면 binding_1 및 binding_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

bind param 후에 전체 쿼리 문자열을 기록해야하므로 코드의 일부입니다. 희망, 그것은 같은 문제를 가진 모든 사람에게 유용합니다.

/**
 * 
 * @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);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.