4

このクエリは、phpMyAdminに5つの結果を返します。

SELECT * FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT 0,5

そして、これはphpMyAdminでcount = 12を返します(12のレコードがあるので問題ありません):

SELECT COUNT(*) AS count FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT 0,5

この関数は、2つの変数(offset、display)を追加する前は正常に機能していましたが、現在は機能していません。変数を出力すると、offset = 0、display = 5になります(それでもLIMIT 0,5)。

function getProducts($offset, $display) {
    $sql = "SELECT * FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT ?,?;";
    $data = array((int)$offset, (int)$display);
    $rows = dbRowsCount($sql, $data);
logErrors("getProducts(".$offset.",".$display.") returned ".$rows." rows.");
    if ($rows > 0) {
        dbQuery($sql, $data);
        return dbFetchAll();
    } else {
        return null;
    }
}

私のdbRowsCount(...)メソッドが空の文字列(stupid PDOStatement::fetchColumn)を返していたために機能していなかったので、カウントを返すように変更し、PDO::FETCH_ASSOCcount=0を返しました。

行数をカウントする関数は次のとおりです。

function dbRowsCount($sql, $data) {
    global $db, $query;
    $regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/is';
    if (preg_match($regex, $sql, $output) > 0) {
        $query = $db->prepare("SELECT COUNT(*) AS count FROM {$output[1]}");
logErrors("Regex output: "."SELECT COUNT(*) AS count FROM {$output[1]}");
        $query->setFetchMode(PDO::FETCH_ASSOC);
        if ($data != null) $query->execute($data); else $query->execute();
        if (!$query) {
            echo "Oops! There was an error: PDOStatement returned false.";
            exit;
        }
        $result = $query->fetch();
        return (int)$result["count"];
    } else {
logErrors("Regex did not match: ".$sql);
    }
    return -1;
}

私のエラーログは私にプログラムからのこの出力を与えます:

正規表現の出力:SELECT COUNT(*)AS count FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT?、?;
getProducts(0,5)は0行を返しました。

ご覧のとおり、SQLの形式は正しくなく、メソッドの入力変数は予想どおり0と5でした。

何がうまくいかなかったのか誰か知っていますか?

アップデート

提案に従って、クエリを直接実行しようとしましたが、正しい結果が返されました。

function dbDebugTest() {
    global $db;
    $stmt = $db->query("SELECT COUNT(*) AS count FROM tbl_product WHERE 1 ORDER BY last_update LIMIT 0,5;");
    $result = $stmt->fetch();
    $rows = (int)$result["count"];
    logErrors("dbDebugTest() returned rows=".$rows);
}

出力:

> dbDebugTest() returned rows=12

別の提案に従って、!= nullを!== nullに変更し、$data配列も出力しました。

logErrors("Data: ".implode(",",$data));
if ($data !== null) $query->execute($data); else $query->execute();

出力:

> Data: 0,5

ただし、dbRowsCount($ sql、$ data)は、このクエリに対して0行を返します。

アップデート2

値がバインドされた後にクエリを出力できるカスタムPDOStatementクラスを実装するためのアドバイスに従って、$ query-> execute($ data)の後で関数が停止するため、出力は出力されないことがわかりました。カスタムクラスは、私のプログラムの他のすべてのクエリに対して機能します。

更新されたコード:

function dbRowsCount($sql, $data) {
    global $db, $query;
    $regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/is';
    if (preg_match($regex, $sql, $output) > 0) {
        $query = $db->prepare("SELECT COUNT(*) AS count FROM {$output[1]}");
logErrors("Regex output: "."SELECT COUNT(*) AS count FROM {$output[1]}");
        $query->setFetchMode(PDO::FETCH_ASSOC);
logErrors("Data: ".implode(",",$data));
        $query->execute($data);
logErrors("queryString:".$query->queryString);
logErrors("_debugQuery():".$query->_debugQuery());
        if (!$query) {
            echo "Oops! There was an error: PDOStatement returned false.";
            exit;
        }
        $result = $query->fetch();
        return (int)$result["count"];
    } else {
logErrors("Regex did not match: ".$sql);
    }
    return -1;
}

出力:

正規表現の出力:SELECT COUNT()AS count FROM tbl_product_category WHERE id = ?;
データ:5
queryString:SELECT COUNT(
)AS count FROM tbl_product_category WHERE id = ?;
_debugQuery():SELECT COUNT(*)AS count FROM tbl_product_category WHERE id = ?;

正規表現の出力:SELECT COUNT(*)AS count FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT?、?;
データ:0,5
//関数が停止し、_debugQueryを出力できませんでした

アップデート3

getProducts(...)カスタムPDOStatementクラスを取得して出力を取得できなかったため、代わりに名前付きプレースホルダーを使用してパラメーターをバインドするようにクラスを書き直したいと思いました。

function getProducts($offset, $display) {
    $sql = "SELECT * FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT :offset, :display;";
    $data = array(':offset'=>$offset, ':display'=>$display);
    $rows = dbRowsCount($sql, $data);
logErrors("getProducts(".$offset.",".$display.") returned ".$rows." rows.");
    if ($rows > 0) {
        dbQuery($sql, $data);
        return dbFetchAll();
    } else {
        return null;
    }
}

出力:

正規表現の出力:SELECT COUNT(*)AS count FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT:offset、:display;
データ:0,5
// $ query-> execute($ data)の後もクラッシュするため、出力logErrors("getProducts(".$offset."...))されませんでした

アップデート4

このdbDebugTestは、以前はSQL文字列で直接制限値0,5を宣言することで機能していました。これで、パラメーターを適切にバインドするように更新しました。

function dbDebugTest($offset, $display) {
    logErrors("Beginning dbDebugTest()");
    global $db;
    $stmt = $db->prepare("SELECT COUNT(*) AS count FROM tbl_product WHERE 1 ORDER BY last_update LIMIT :offset,:display;");
    $stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
    $stmt->bindParam(':display', $display, PDO::PARAM_INT);
    if ($stmt->execute()) {
      $result = $stmt->fetch();
      $rows = (int)$result["count"];
      logErrors("dbDebugTest() returned rows=".$rows);
    } else {
      logErrors("dbDebugTest() failed!");
    }
}

関数がクラッシュし、これだけが出力されます。

dbDebugTest()の開始

アップデート5

エラーをオンにする(デフォルトではオフになっている)という提案に従って、私はこれを行いました:

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

それ自体が、Update 4のdbDebugTest()を機能させました。

dbDebugTest()の開始dbDebugTest()はrows=12を返しました

そして今、私のウェブサーバーのログにエラーが生成されます:

[警告]mod_fcgid:stderr:PHP致命的なエラー:
キャッチされない例外'PDOException'とメッセージ'SQLSTATE [42000]:
構文エラーまたはアクセス違反:1064SQL構文にエラーがあります。 /home/linweb09/b/example.com-1050548206/user/my_program/database/ の1行目の「0」、「5」の近く
で使用する正しい構文については、MySQLサーバーのバージョンに対応するマニュアルを確認してください。dal.php:36

36行目dbRowsCount(...)はメソッドを示し、行は$query->execute($data)です。

したがって、他の方法getProducts(...)は、データをバインドするこの方法を使用し、パラメーターが「0」と「5」に変わるため、まだ機能しません(これはバグですか?)。少し面倒ですが、dal.phpに新しいメソッドを作成して、より厳密な方法でparamsをバインドできるようにする必要がありbindParamます。

特に@Travesty3と@eggyalの助けに感謝します!! どうもありがとうございました。

4

2 に答える 2

2

質問の更新2に基づくと、executeステートメントの後に実行が停止するため、クエリが失敗しているように見えます。いくつかのPDOドキュメントを見ると、デフォルトのエラー処理設定はPDO :: ERRMODE_SILENTであるように見えます。これにより、表示されている動作が発生します。

これは、この投稿で発生したように、パラメータとして渡されたときにLIMIT句の数値が一重引用符で囲まれていることが原因である可能性があります。

その投稿の解決策は、bindValueメソッドを使用してパラメーターを整数として指定することでした。したがって、おそらく同様のことを行う必要があります。

また、MySQLエラーをキャッチするには、try-catchブロックを使用してクエリを実行する必要があるようです。


bindValueメソッド:

if ($data !== null)
{
    for ($i=0; $i<count($data); $i++)
        $query->bindValue($i+1, $data[$i], PDO::PARAM_INT);
    $query->execute($data);
}
else
    $query->execute();
于 2012-05-01T18:44:45.320 に答える
1

恒等演算子ではなく、等式演算子を使用しているかどうかをテストしています(さまざまな比較演算子による値の処理方法の詳細については、PHPのマニュアルを参照$dataしてください)IDテスト/を使用するか、またはを呼び出す必要があります。NULLNULL===!==is_null()

上記の@Travesty3のように、配列が空かどうかをテストするには、を使用しますempty()

于 2012-05-01T17:25:13.263 に答える