PDOの準備済みステートメントから生のSQLクエリ文字列を取得する


130

準備済みステートメントでPDOStatement :: execute()を呼び出すときに実行される生のSQL文字列を取得する方法はありますか?これはデバッグの目的で非常に役立ちます。


1
PHP> = 5.1の場合は、php.net
manual /

1
1行の関数pdo-debugを確認してください。
Sliq 2014

私が見つけた最もクリーンな方法は、E_PDOStatementライブラリです。あなたがするだけ$stmt = $pdo->prepare($query); /* ... */ echo $stmt->fullQuery;。これはPDOStatementクラスを拡張することで機能するため、PDO APIで可能な限りエレガントです。
ComFreek

回答:


110

パラメータ値が補間された最後のSQLクエリが必要だと思います。これはデバッグに役立つことを理解していますが、準備されたステートメントが機能する方法ではありません。パラメータはクライアント側で準備されたステートメントと組み合わされないので、PDOはそのパラメータと組み合わされたクエリ文字列にアクセスできません。

SQLステートメントはprepare()を実行するとデータベースサーバーに送信され、パラメーターは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()するとクエリ全体を送信します。 これは真の準備済みクエリではありません。 execute()の前に変数をSQL文字列に補間することにより、準備済みクエリの利点を回避します。


@afilinaからの再コメント:

いいえ。テキストSQLクエリは、実行中にパラメータと結合されません。したがって、PDOが表示するものはありません。

内部的には、PDO :: ATTR_EMULATE_PREPARESを使用する場合、PDOはSQLクエリのコピーを作成し、準備と実行を行う前にパラメーター値をその中に挿入します。ただし、PDOはこの変更されたSQLクエリを公開しません。

PDOStatementオブジェクトには$ queryStringプロパティがありますが、これはPDOStatementのコンストラクターでのみ設定され、クエリがパラメーターで書き換えられたときに更新されません。

書き換えられたクエリを公開するようにPDOに要求することは、PDOにとって妥当な機能要求です。しかし、PDO :: ATTR_EMULATE_PREPARESを使用しない限り、それでも「完全な」クエリは得られません。

これが、MySQLサーバーの一般的なクエリログを使用する上記の回避策を示している理由です。この場合、パラメータープレースホルダーを使用して準備されたクエリでも、パラメーター値がクエリ文字列にバックフィルされ、サーバーで書き換えられます。ただし、これはロギング中にのみ行われ、クエリの実行中には行われません。


10
そして、PDO :: ATTR_EMULATE_PREPARESがTRUEに設定されている場合、どのようにしてホールクエリを取得しますか?
Yasen Zhelev 2011年

2
@Yasen Zhelev:PDOが準備をエミュレートしている場合、クエリを準備する前にパラメータ値をクエリに補間します。そのため、MySQLはパラメータープレースホルダーを含むクエリのバージョンを見ることはありません。MySQLは完全なクエリのみをログに記録します。
ビルカーウィン、2011年

2
@ビル:「パラメータはクライアント側で準備されたステートメントと組み合わされていません」-待ってください-しかし、それらはサーバー側で組み合わされますか?または、mysqlはどのように値をDBに挿入しますか?
スタン

1
@afilina、いいえ、できません。上記の私の説明を参照してください。
ビルカーウィン

3
うわー、反対票?メッセンジャーを撃たないでください。私はそれがどのように機能するかを説明しているだけです。
ビルカーウィン2014

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、2014年

これの使い方は何ですか?

立ち寄って私の感謝を申し上げたかっただけなのですが、このための追加のクラス全体ではありませんでした。とても小さくて素晴らしいので、これを優先して削除しました:)。そのため、アプリケーションが各ページで実行するすべてのクエリをログに記録してデバッグするのに便利です:D
NaughtySquid

この機能を見て、私は理解していない何かが、なぜあなたはチェックしますが、それは、私は非常に満足して作られ$keyているためstringではなく$value?何か不足していますか?この出力の、2番目のパラメータは文字列として見られていないので、私はこれを尋ねる理由は次のとおりです。string(115) "INSERT INTO tokens (token_type, token_hash, user_id) VALUES ('resetpassword', hzFs5RLMpKwTeShTjP9AkTA2jtxXls86, 1);"
KerwinいつSneijders

1
これは良いスタートですが、$ param自体の値に疑問符( "?")が含まれていると失敗します。
チキンチリ

32

WHERE IN(?)などのステートメントの配列の出力を処理するようにメソッドを変更しました。

更新:NULL値のチェックを追加し、$ paramsを複製したため、実際の$ param値は変更されません。

bigwebguy、ありがとうございます。

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

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

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

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

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

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

    return $query;
}

2
$values = $params;代わりにあなたがしなければならないと思います$values = array()
2012

ここで見逃されているもう1つの小さなピースは弦です。それらをキャプチャするためには、上記の本を置くis_arrayチェック:if (is_string($value)) $values[$key] = "'" . $value . "'";
treeface

これは、preg_replaceのバインド値が1回だけに制限されています。この行$values = $params; $values_limit = []; $words_repeated = array_count_values(str_word_count($sql, 1, ':_')); を最初に追加した後、この内部を最初に追加した後、foreach $values_limit[$key] = (isset($words_repeated[':'.$key]) ? intval($words_repeated[':'.$key]) : 1);とthis in first else in foreach $values_limit = [];use foreach loop $ values to again preg_replace withisset($values_limit[$key])
vee

たとえばループ$ values。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]:構文エラーまたはアクセス違反:[...]の近くに'ELECT *人FROM WHERE年齢= 18'行1で

クエリの最初の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値を持つ文字列または整数であるかどうかを検証するためにいくつかの変更を行いました。
セルジオフローレス

どこで見られる?
モーグはモニカを2014

8

PDOStatementにはパブリックプロパティ$ queryStringがあります。それはあなたが望むものでなければなりません。

PDOStatementにはドキュメント化されていないメソッドdebugDumpParams()があり、これも確認したい場合があることに気づきました。


1
debugDumpParamsは文書化されていませんphp.net/manual/en/pdostatement.debugdumpparams.php
mloskot

いいえ。$ queryStringは、含まれているパラメーター値を表示しません。
Andreas

5

PDOStatementクラスを拡張して、バインドされた変数をキャプチャーし、後で使用するために保存できます。次に、2つのメソッドを追加できます。1つは変数のサニタイズ用(debugBindedVariables)、もう1つはこれらの変数を使用してクエリを出力するため(debugQuery)です。

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

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

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

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

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

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

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

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

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

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

    return $vars;
  }

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

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

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

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

    echo $queryString.PHP_EOL;
  }
}


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

そして、この継承されたクラスを目的のデバッグに使用できます。

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

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

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

その結果

SELECT FROM user FROM users WHERE user = 'user_test'

配列([:test] => user_test)


4

私は自分のニーズのためにこの状況を調査するのにかなりの時間を費やしました。これと他のいくつかのSOスレッドが私を大いに助けたので、私が思いついたものを共有したいと思いました。

補間されたクエリ文字列にアクセスできることはトラブルシューティング中の大きなメリットですが、特定のクエリのみのログを維持できるようにしたいと考えました(したがって、この目的でデータベースログを使用することは理想的ではありませんでした)。また、ログを使用していつでもテーブルの状態を再現できるようにしたいと考えていたため、補間された文字列が適切にエスケープされるようにする必要がありました。最後に、この機能をコードベース全体に拡張して、可能な限り書き直さなくても済むようにしました(期限、マーケティングなど、ご存知でしょう)。

私の解決策は、デフォルトのPDOStatementオブジェクトの機能を拡張してパラメーター化された値(または参照)をキャッシュし、ステートメントが実行されたときにPDOオブジェクトの機能を使用して、パラメーターがクエリに注入されたときにパラメーターを適切にエスケープすることでしたストリング。次に、statementオブジェクトのexecuteメソッドに関連付けて、その時点で実行された実際のクエリをログに記録します(または、少なくとも可能な限り忠実に再現します)

すでに述べたように、この機能を追加するためにコードベース全体を変更したくなかったため、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@マイククリス・ゴー@、それらのすべては、この質問の答え):

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

「再利用」バインド値を使用するまで、マイクの答えはうまくいきます。
例えば:

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)

マイクの答えは最初の:searchを置き換えるだけで、2番目は置き換えられません。
したがって、私は彼の答えを書き直して、適切に再利用できる複数のパラメーターを処理できるようにします。

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.