3

PDOを操作するのが面倒なのは、いくつかの変数が欠落していると言うことです。

PDOStatement :: execute():SQLSTATE [HY093]:無効なパラメーター番号:バインドされた変数の数がトークンの数と一致しません

...しかし、どれかはわかりません。それらを特定するための解決策はありますか?例えば

$sql = "SELECT id, name WHERE id = :id AND name like  :search_tem";

$stmt = $pdo->prepare($sql);
$stmt->bindValue(':id', '1');
$stmt->execute(); // throws exception - "**search_term missing"

誰もがこのようなものを必要としていることは明らかです。しかし、私は簡単な解決策はできません。

4

4 に答える 4

2

評判が低いため、直接コメントすることはできません。したがって、これを2013年1月19日の15:58のRagenDazsの投稿への返信として想像してみてください。私はこのトピックが数日前であることを知っています、しかし私のような誰かがグーグル検索によってこれにつまずいたら...

ただし、最後から3行目の正規表現に問題がありました。この例でわかるように、式は時刻として00:00:00の時刻値にも一致します。したがって、このの正規表現を使用することをお勧めします。

また、不要なパラメータがあるかどうかも知りたいと思いました。これが私が行った方法です。上記の例のようなSQLクエリとパラメータ配列が必要です(PDOStatement :: executeについてはphpドキュメントの例2を参照してください)。

    /**
 * Checks an parameter array against the sql query. it will tell you if there are any missing or needless parameters
 *
 * @param string $query      Sql query
 * @param array  $parameters Parameters array
 *
 * @return bool|array Returns TRUE if no missing or needless parameters where found or a list with the missing
 *                    or needless parameters
 */
private function checkParameters($query, $parameters)
{
    $parameterTMP = $parameters;
    $parameterCount = count($parameterTMP);
    $regexMatchCounter = preg_match_all("/:[^]\\D\\w*/", $query, $regexMatches);

    // if there are parameter in the $parameters array oder parameters in the sql query
    if( $parameterCount > 0 || $regexMatchCounter > 0 )
    {
        // take every parameter found in the sql query
        foreach( $regexMatches[ 0 ] as $parameterName )
        {
            // check if the required parameter is in the parameters array
            if( !array_key_exists($parameterName, $parameters) )
            {
                // if it is not in the parameters array, add it to the list of missing parameters
                // and continue with the next parameter from the query
                $result[ 'missing' ][] = $parameterName;
                continue;
            }

            // if the required parameter is in the parameter array, delete it from this array
            // so we get a list of parameters that are needless
            unset($parameterTMP[ $parameterName ]);
        }

        // check if there are (needless) parameters left
        if( count($parameterTMP) > 0 )
        {
            // if so, add them to the list of needles parameters
            $result[ 'needless' ] = array_keys($parameterTMP);
        }

        // if at this point $result is an array,
        // some parameters are missing or needless, so we return the result list(s)
        if( isset($result) && is_array($result) )
        {
            return $result;
        }
    }

    // if we reach this point, no missing or needless parameters where found,
    // you are good to go
    return true;
}

何かが間違っている場合に例外をスローしたい場合は、「return$result;」を置き換えてください。次のコード行を使用します。

    $missingCount = 0;
    $missing = "";

    $needlessCount = 0;
    $needless = "";

    if( array_key_exists('missing', $parameters) )
    {
        $missingCount = count($parameters[ 'missing' ]);
        $missing = " (" . implode(", ", $parameters[ 'missing' ]) . ") ";
    }

    if( array_key_exists('needless', $parameters) )
    {
        $needlessCount = count($parameters[ 'needless' ]);
        $needless = " (" . implode(", ", $parameters[ 'needless' ]) . ")";
    }

    $msg = "There are " . $missingCount . " missing parameter(s)".$missing." and ".$needlessCount." needless parameter(s)".$needless.".";

    throw new Exception($msg);

楽しんで。

于 2017-01-20T10:34:59.960 に答える
1

名前付きプレースホルダーは、クエリとプレースホルダーの視覚的な検証を容易にするために、特にこの目的のためにPDOチームによって発明されたと言えます。

私は同意する必要があります、そのような機能はある種の構文エラーシュガーである可能性がありますが、正直なところ、私はそれがあまり有用であるとは思いません。you have an error near ''欠落しているプレースホルダーを見つけることはそれほど大したことではありませんが、 (1つのように)はるかに不可解な他のエラーがあります。

于 2013-01-16T13:01:47.137 に答える
1

このテーマについて数日検索した後、私がこの解決策を見つけたいくつかのものをテストしました-私のデータベースクラスbindのメソッドからのコードに従ってください:

// [Method from Class Database]

/**
 * @param PDOStatement stmt
 * @param array data
 * @throws Exception if some variables are missing when interpolate query
 * @example $db->bind($stmt, $_POST)
 */
function bind(&$stmt, $data) {
    $sql = $stmt->queryString;
    // Sort $data keys to prevent erroneus bind parameters
    ksort($data);
    $data = array_reverse($data);
    foreach ($data as $_key => $_val) {
        if (preg_match("/:$_key/", $sql)) {
            $stmt->bindParam(":$_key", $data[$_key]);
            $sql = preg_replace("/:$_key/", $this->dbh->quote($data[$_key]), $sql, 1);
        }
    }

    //  if ($this->debug) {
    //      $this->fb->info($sql, 'SQL');
    //      $this->fb->info($stmt, 'Statment');
    //      $this->fb->info($data, 'Raw Data');
    //  }

    if (strpos($sql, ":")) {
        $matches = array();
        $this->dbg = preg_match_all('/:[A-Za-z0-9_]*/', $sql, $matches);
        throw new Exception('PDO Missing variables: ' . implode(', ', $matches[0]));
    }
}

このコードは改訂が必要です。誰かがバグを見つけたり、何かを改善したりした場合は、共有してください。

于 2013-01-19T15:58:23.007 に答える
0

更新された回答

初めて質問を読み間違えたので、あなたが何を望んでいるのか理解できました。私が見る限り、エラーメッセージはPDO例外によって定義されているため、これは不可能です。

ただし、回避策として、PDOのラッパークラスを記述し、バインドされた値を確認して自分でクエリを実行し、不足している値がある場合は、独自の例外をスローすることができます。これはおそらくこれを達成するための最良の方法です...

元の回答

誰もがこのようなものを必要としていることは明らかです。しかし、私は簡単な解決策はできません。

私はこれに同意しません。この種の機能を追加しても意味がありません。このことを考慮:

"SELECT id, name WHERE id = '1' AND name like  "

これは、許可された場合にコードが出力するものです。用語には何も書かれていないので、明らかに上記は機能しませLIKE

私も過去に値をバインドすることを(意図的および意図せずに)忘れていたので、なぜこれが必要なのか理解できますが、値をバインドしないとクエリが機能しないため、実際にはメリットがありません。

次のように動的にクエリを作成する方がはるかに良いでしょう。

// Gather the where parameters
$get_data_where = array();

// Field 2
if(!empty($parameters['field_1'])){
    $get_data_where[':field_1'] = '%'.$parameters['field_1'].'%';
}           
// Field 2
if(!empty($parameters['field_2'])){
    $get_data_where[':field_2'] = $parameters['field_2'];
}   

// Combine the where array with the bind valus array
$this->mssql->bind_values = array_merge($this->mssql->bind_values,$get_data_where);

// Prepare the SQL to gather the data
$SQL  = "SELECT * \n";
$SQL .= "FROM [Some_Table] AS ST \n";

// Append the where statement if necessary
// Build the where statement based on bind values
if(!empty($get_data_where)){
    $SQL .= "WHERE \n\t";

    // Field 1
    if(!empty($this->mssql->bind_values[':field_1'])){
        $SQL .= $where_and."ST.[Field_1] LIKE :field_1 \n\t";
        // Separate the where conditions
        $where_and = "AND ";
    }               
    // Field 2
    if(!empty($this->mssql->bind_values[':field_2'])){
        $SQL .= $where_and."ST.[Field_2] = :field_2 \n\t";
        // Separate the where conditions
        $where_and = "AND ";
    }
}
于 2013-01-16T12:12:49.587 に答える