0

私のコードは現在、を使用mysqli::queryしてチェックしていますmysqli::$warning_count。整数列にテキストを挿入しようとすると、0が挿入され、警告が生成されます。ただし、準備されたステートメントを学習し始めたばかりで、同じクエリに対して警告は生成されません。

これが私のコードからの抜粋です:

$db_err_msg = 'Database Error: Failed to update profile';
$sql = "UPDATE tblProfiles SET intBookId = ? WHERE lngProfileId = ?";
$stmt = $mysqli->prepare($sql) or output_error($db_err_msg);

$book = 'CA';
$id = 10773;
$stmt->bind_param('ii', $book, $id) or output_error($db_err_msg);
$stmt->execute() or output_error($db_err_msg);
echo '$stmt->affected_rows is ', $stmt->affected_rows, "\n";

if ($mysqli->warning_count) {
    $warnings = $stmt->get_warnings();
    do {
        trigger_error('Database Warning (' . $warnings->errno . '): '
            . $warnings->message, E_USER_WARNING);
    } while ( $warnings->next() );
}
else {
    echo 'no warnings', "\n";
}

次の出力が生成されます。

$stmt->affected_rows は 1
警告なし

intBookId列にはTINYINTデータ型があることに注意してください。を使用すると同じクエリで警告が生成されますが、mysqli::query準備済みステートメントを使用すると警告が生成されません。

厳密モードを有効にしても役に立ちません。を使用すると警告がエラーに変わりますmysqli::queryが、準備されたステートメントを使用すると、列は暗黙のうちに0;で更新されます。

記録のために、私のアプリケーションは、この時点に到達する前にすでに広範な検証を行っています。しかし、誤って見逃してしまう可能性のあるものをキャッチする方法として、この追加の検証が必要でした。

注: PDO に切り替えることは、現在のプロジェクトの範囲を超えています。

MySQLi のプリペアド ステートメントでこの問題が発生するのはなぜですか? これは予想される動作ですか?

4

1 に答える 1

1

すぐにはわからないかもしれませんが、これは予期される動作です。

このコード行のために:

$stmt->bind_param('ii', $book, $id) or output_error($db_err_msg);

PHP は、値を MySQL に送信する前に整数にキャストしています。MySQL は0、列の有効な値である値を受け取り、警告は生成されません。

PHP にこれを行わせたくない場合は、文字列として送信する必要があります。そのようです:

$stmt->bind_param('si', $book, $id) or output_error($db_err_msg);

MySQL は文字列「CA」を受け取り、それが正しくない整数値であるという警告を生成します。

注:すべてを文字列として送信することにより、MySQL は文字列を整数に変換するためにもう少し処理を行う必要がありますが、mysqli::query を使用してクエリ全体が文字列として送信されたとき、MySQL はすでに処理を行っていました。

注:より大きい整数を使用すると、関連する問題が発生しますPHP_INT_MAX。整数値がその最大値 (プラットフォームに依存し、32 ビット プラットフォームでは 2147483647 のみ) を超え、精度が重要であると思われる場合は、文字列として送信する方が安全です。

于 2012-12-16T12:54:09.580 に答える