복붙노트

[SQL] PDO 준비된 문을에서 원시 SQL 쿼리 문자열 얻기

SQL

PDO 준비된 문을에서 원시 SQL 쿼리 문자열 얻기

PDOStatement이 :: 준비된 문에 () 실행 호출 할 때 실행되는 원시 SQL 문자열을 얻을 수있는 방법이 있나요? 디버깅 목적으로이 매우 유용 할 것이다.

해결법

  1. ==============================

    1.난 당신이 매개 변수 값은 그것으로 보간 당신이 최종 SQL 쿼리를 원하는 뜻 가정합니다. 나는이 디버깅에 유용 할 것이라는 점을 이해하지만,이 방법 문 준비 작업이 아니다. PDO는 매개 변수와 함께 쿼리 문자열에 액세스 할 수 없습니다 안 있도록 매개 변수는 클라이언트 측에 준비된 명령문과 결합되지 않습니다.

    난 당신이 매개 변수 값은 그것으로 보간 당신이 최종 SQL 쿼리를 원하는 뜻 가정합니다. 나는이 디버깅에 유용 할 것이라는 점을 이해하지만,이 방법 문 준비 작업이 아니다. PDO는 매개 변수와 함께 쿼리 문자열에 액세스 할 수 없습니다 안 있도록 매개 변수는 클라이언트 측에 준비된 명령문과 결합되지 않습니다.

    SQL 문은 당신이 (준비합니까 데이터베이스 서버)로 전송하고 실행 할 때 매개 변수가 별도로 전송됩니다 (). MySQL의의 일반 쿼리 로그는 실행 후 보간 값을 최종 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를 설정하면 당신이 원하는 것을 얻을 수 있습니다. 이 모드에서 SQL 쿼리로 보간 매개 변수를 PDO 및 실행 전체 쿼리 ()를 보냅니다. 이것은 진정한 준비 쿼리하지 않습니다. 당신은 실행하기 전에 SQL 문자열로 변수를 보간하여 준비된 쿼리의 혜택을 회피한다 ().

    @afilina에서 코멘트 재 :

    아니, 텍스트 SQL 쿼리가 실행 중에 매개 변수와 결합되지 않습니다. 그래서 PDO 당신을 보여 할 것도 없다.

    당신이 PDO :: ATTR_EMULATE_PREPARES를 사용하는 경우 내부적으로, PDO는 준비하고 실행하기 전에 그것으로 값 매개 변수 SQL 쿼리 및 보간의 복사본을 만듭니다. 그러나 PDO는이 수정 SQL 쿼리를 노출하지 않습니다.

    PDOStatement 객체는 속성 $ queryString이있다, 그러나 이것은 PDOStatement에 대한 생성자 만 설정하고 쿼리 매개 변수를 사용하여 다시 작성 될 때 업데이트 아니에요.

    PDO는 다시 쿼리를 노출하도록 요청하는 것은 합리적인 기능 요청 될 것이다. 당신이 PDO :: ATTR_EMULATE_PREPARES을 사용하지 않는 그러나 심지어 당신에게 "완전한"쿼리를 제공하지 않을 것입니다.

    이 경우 매개 변수 자리 표시 심지어 준비된 쿼리 서버에서 다시 때문에 매개 변수 값은 쿼리 문자열로 채웠다와 나는, MySQL 서버의 일반 쿼리 로그를 사용하여 위의 해결 방법을 보여 이유입니다. 그러나 이것은뿐만 아니라 쿼리 실행 중, 로깅 동안 이루어집니다.

  2. ==============================

    2.

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

    3.나는 문에 배열의 출력을 처리 포함하는 방법을 수정 같은 WHERE IN (?).

    나는 문에 배열의 출력을 처리 포함하는 방법을 수정 같은 WHERE IN (?).

    UPDATE : 그냥 NULL 값에 대한 검사를 추가하고 실제 $의 PARAM 값이 수정되지 않도록 $에게 PARAMS 중복.

    위대한 작업 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;
    }
    
  4. ==============================

    4.작은 따옴표를 추가 할 값을 걸어 - 조금 마이크에 의해 코드에 더 많은 비트 추가

    작은 따옴표를 추가 할 값을 걸어 - 조금 마이크에 의해 코드에 더 많은 비트 추가

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

    5.A는 아마 늦게 비트하지만 지금 PDOStatement :: debugDumpParams있다

    A는 아마 늦게 비트하지만 지금 PDOStatement :: debugDumpParams있다

    당신은 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();
    
    ?>
    
  6. ==============================

    6.PDOStatement는 공공 재산 $ queryString이 있습니다. 그것은 당신이 원하는 것을해야한다.

    PDOStatement는 공공 재산 $ queryString이 있습니다. 그것은 당신이 원하는 것을해야한다.

    난 당신이 또한보고 할 수 있습니다 PDOStatement이 문서화되지 않은 방법 debugDumpParams을 가지고 단지 통지를 ()했습니다.

  7. ==============================

    7.해결책은 자발적으로 쿼리에서 오류를 넣어 및 오류의 메시지를 인쇄하는 것입니다 :

    해결책은 자발적으로 쿼리에서 오류를 넣어 및 오류의 메시지를 인쇄하는 것입니다 :

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

    표준 출력 :

    단지 쿼리의 첫 80 개 문자를 인쇄하는 것이 중요합니다.

  8. ==============================

    8.나는 내 자신의 요구에이 문제를 연구하는 많은 시간을 보냈다. 내가 해낸 공유하기를 원해요 그래서이 여러 다른 SO 스레드는 나에게 많은 도움이되었습니다.

    나는 내 자신의 요구에이 문제를 연구하는 많은 시간을 보냈다. 내가 해낸 공유하기를 원해요 그래서이 여러 다른 SO 스레드는 나에게 많은 도움이되었습니다.

    보간 된 쿼리 문자열에 대한 액세스 권한을 갖는 문제 해결 동안 큰 이점이 있지만, 우리는 (이상적인 아니었다 이러한 목적을 위해 데이터베이스 로그를 사용하므로) 특정 쿼리의 로그를 유지할 수 싶었다. 우리는 또한 그러므로 우리가 어떤 보간 된 문자열을 올바르게 이스케이프 된 만드는 데 필요한, 주어진 시간에 테이블의 상태를 다시 로그를 사용할 수있게하고 싶었다. 마지막으로, 우리는 우리의 전체 코드베이스 가능한 한 거의 같은 재 작성할 필요에이 기능을 확장하고 싶어 (마감, 마케팅, 등, 당신은 얼마나 알고있다).

    내 솔루션은 매개 변수 값 (또는 참조) 캐시 할 기본 PDOStatement 객체의 기능을 확장 할 수 있었고, 명령문이 실행될 때이 쿼리에 다시 주입하는 경우, 매개 변수를 탈출 제대로에 PDO 개체의 기능을 사용 끈. 그러면 문 객체의 메소드를 실행하고 (또는 적어도 가능한 재생의 충실) 그 시점에서 실행 된 실제 쿼리 로그에 묶을 수있다.

    내가 말했듯이, 우리는 우리가 다음 부모 전화, 기본 bindParam ()와 bindValue ()를 PDOStatement 객체의 방법, 바인딩 된 데이터의 우리의 캐싱을 덮어 쓰기 때문에,이 기능을 추가하기 위해 전체 코드베이스를 수정하지 않았다 : bindParam () 또는 부모 :: bindValue (). 이것은 정상적인 역할을 계속하기 위해 기존의 코드베이스를 허용했다.

    실행] () 메서드를 호출 할 때 마지막으로, 우리는 우리의 보간을 수행하고 새 속성 E_PDOStatement-> fullQuery로 결과 문자열을 제공합니다. 이 로그 파일에 기록 예를 들어 쿼리 또는, 볼 수있는 출력 할 수 있습니다.

    확장, 설치 및 구성 지침과 함께, GitHub의에서 사용할 수 있습니다 :

    https://github.com/noahheck/E_PDOStatement

    기권: 내가 언급 한 바와 같이 분명히, 나는이 확장을 썼다. 이 여기에 많은 스레드의 도움으로 개발 되었기 때문에, 내가했던 것처럼, 다른 사람이 이러한 스레드를 통해 오는 경우 여기에 내 솔루션을 게시하고 싶었다.

  9. ==============================

    9.당신은 제한된 변수를 캡처하고 나중에 사용할 수 있도록 저장하는 PDOStatement 클래스를 확장 할 수 있습니다. 이어서 2 방법은 그 변수 (debugQuery)와 질의를 인쇄하는 가변 살균 (debugBindedVariables) 용, 다른 하나를 첨가 될 수있다 :

    당신은 제한된 변수를 캡처하고 나중에 사용할 수 있도록 저장하는 PDOStatement 클래스를 확장 할 수 있습니다. 이어서 2 방법은 그 변수 (debugQuery)와 질의를 인쇄하는 가변 살균 (debugBindedVariables) 용, 다른 하나를 첨가 될 수있다 :

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

    를 야기하는

  10. ==============================

    10.언급 된 $의 검색어 문자열 속성은 아마 단지 자신의 값으로 대체 매개 변수없이 전달 된 질의를 반환합니다. 닷넷, 나는 간단한 검색 오류 로그 쿼리에 사용되는 한 실제 값을 표시 할 수 있도록 제공된 자신의 값으로 매개 변수를 대체 할 실행자 내 쿼리의 캐치 부분이있다. 당신은 PHP의 매개 변수를 열거하고, 할당 된 값으로 매개 변수를 대체 할 수 있어야한다.

    언급 된 $의 검색어 문자열 속성은 아마 단지 자신의 값으로 대체 매개 변수없이 전달 된 질의를 반환합니다. 닷넷, 나는 간단한 검색 오류 로그 쿼리에 사용되는 한 실제 값을 표시 할 수 있도록 제공된 자신의 값으로 매개 변수를 대체 할 실행자 내 쿼리의 캐치 부분이있다. 당신은 PHP의 매개 변수를 열거하고, 할당 된 값으로 매개 변수를 대체 할 수 있어야한다.

  11. ==============================

    11.이 질문은 조금 오래 알고 있지만, 나는 많은 시간 전부터이 코드를 (I 크리스 - 이동 @로부터 응답을 사용했습니다) 사용하고, 지금,이 코드는 PHP 7.2과 함께 사용되지 않습니다

    이 질문은 조금 오래 알고 있지만, 나는 많은 시간 전부터이 코드를 (I 크리스 - 이동 @로부터 응답을 사용했습니다) 사용하고, 지금,이 코드는 PHP 7.2과 함께 사용되지 않습니다

    나는이 코드의 업데이트 된 버전을 게시합니다 (@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_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 (과 희망의 미래 버전도)와 호환합니다.

  12. ==============================

    12.다소 관련 ... 당신은 당신이 PDO를 사용할 수있는 특정 변수 :: 견적을 소독하려고합니다. 당신이 CakePHP를 같이 제한된 프레임 워크와 붙어있어 예를 들어, 여러 부분 LIKE 조건을 검색합니다 :

    다소 관련 ... 당신은 당신이 PDO를 사용할 수있는 특정 변수 :: 견적을 소독하려고합니다. 당신이 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}%"),
        ),
    );
    
  13. ==============================

    13.당신은 "재사용"바인드 값을 사용하여 때까지 마이크의 대답은 잘 노력하고 있습니다. 예를 들면 :

    당신은 "재사용"바인드 값을 사용하여 때까지 마이크의 대답은 잘 노력하고 있습니다. 예를 들면 :

    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;
    }
    
  14. ==============================

    14.preg_replace이다 나를 위해 일을하지 않았고 binding_ 9 이상 때 ​​내가 뒤로 교체했다, 그래서 binding_1 및 binding_10는 않는 str_replace (0 뒤에 떠나는)로 대체되었다 :

    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;
    

    }

    희망 누군가가 유용 찾습니다.

  15. ==============================

    15.나는이 내 코드의 조각 그래서 바인드 PARAM 후 전체 쿼리 문자열을 로그인해야합니다. 모두 모자 같은 문제를 가지고 희망, 그것은 유용합니다.

    나는이 내 코드의 조각 그래서 바인드 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);
    }
    
  16. ==============================

    16.당신은 sprintf를 사용할 수 있습니다 (없는 str_replace를 ( ' "%의"', $ SQL), ... $ PARAMS '?');

    당신은 sprintf를 사용할 수 있습니다 (없는 str_replace를 ( ' "%의"', $ 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";
    }
    

    > = 5.6 PHP이 단지 작품을 참고

  17. from https://stackoverflow.com/questions/210564/getting-raw-sql-query-string-from-pdo-prepared-statements by cc-by-sa and MIT license