1

正確に言うと、私の検索ステートメントはどれもデータを適切に取得しません。これは独特で、正確なクエリをコピーしてphpMyAdminに入れて実行すると、期待どおりの結果が返されます。

挿入ステートメントなどは、次のように機能します。

    // On first connect to database, create a user to hold data for users not logged in
    $result = $db->query("SELECT id FROM users WHERE id = 1");
    if ($result->num_rows == 0) {
        $db->query("INSERT INTO users (id, username, email, password) VALUES (1, 'anonymous', 'anonymous', '" . password_hash("...", PASSWORD_BCRYPT) . "')");
    }

そして、ユーザーは意図したとおりに入力されます。

しかし、次のようなステートメントを実行すると、次のようになります。

    $result = $db->query("SELECT id, username, password FROM users WHERE email = $email");
    $row = $result->fetch();

次のエラーが発生します:「致命的なエラー:非オブジェクトでのメンバー関数fetch()の呼び出し」

phpMyAdminでまったく同じステートメントを実行すると、意図したとおりに行が返されます。

ただし、1つの領域でのみ機能します。

            if ($result = $db->query("SELECT username, wins, losses FROM users ORDER BY wins DESC LIMIT 10")) {
                while ($row = $result->fetch_assoc()) {
                    echo "<tr><td>" . $row["username"] . "</td> <td>" . $row["wins"] . "</td> <td>" . $row["losses"] . "</td></tr>\n";
                }
            }

意図した結果を返します。でも、理由はわかりません。

ファイルの構造が重要かどうかはわかりません。必要なconfig.phpファイルがあり、接続情報が含まれています。残りは私のindex.phpファイルにあります。

config.phpは次のとおりです。

<?php
    $db_host = $_SERVER["SERVER_NAME"];
    $db_user = "...";
    $db_pass = "...";
    $db_database = "hangman";

    $db = new mysqli($db_host, $db_user, $db_pass, $db_database);

    if ($db->connect_error) {
        echo "Could not connect to database.";
        exit;
    }
    // On first connect to database, create a user to hold data for users not logged in
    $result = $db->query("SELECT id FROM users WHERE id = 1");
    if ($result->num_rows == 0) {
        $db->query("INSERT INTO users (id, username, email, password) VALUES (1, 'anonymous', 'anonymous', '" . password_hash("...", PASSWORD_BCRYPT) . "')");
    }
?>

PHPをもっと含めることができます。何を言ってください。これは、私を夢中にさせているだけです。

4

4 に答える 4

2

エラーが正確に何であるかはわかりません。

不思議ではありません。あなたはこれを求めていませんでした。クエリを実行するときは、常にエラーをチェックする必要があり
ます

$sql = "SELECT wins, losses FROM users WHERE id = 1";
$res = $db->query($sql) or trigger_error($db->error." [$sql]");
$row = $res->fetch_assoc();
于 2013-02-21T19:57:53.670 に答える
2

まず、入力がデータベースからのものである場合でも、自分で入力しなかったデータを信頼してはなりません。

$result = $db->query("SELECT id, username, password FROM users WHERE email = $email");
$row = $result->fetch();

これには構文エラー$emailがあります。文字列であるため、引用符が必要です。

本当に接続しているの$_SERVER["SERVER_NAME"]ですか?
代わりに実際に接続する必要がありlocalhostます...

クエリをテストするためのヒントは、クエリをifブロックでラップすることです。失敗した場合FALSEは、オブジェクトではなく返されるためです。呼び出すことはできませんfalse->fetch()

if ($result = $db->query($sql)) {
    //do stuff, fetch data, etc.
} else {
    if (DEBUG) { // define('DEBUG', 1);
        trigger_error("Query Failed; Fix it: " . htmlspecialchars($sql));
    } else {
        header("Location: /oops.php");
    }
}

また、これにはを使用しprepareます。実際、データを挿入する、またはユーザー入力の期間を含むすべての準備を使用してください。そして、ループの前にそれを定義します。

if ($x = $db->prepare("SELECT id, username, password FROM users WHERE email = ?")) {
    $x->bind_param("s", $email);
    $x->execute();
    $x->bind_result($id, $user, $pass);
    $x->fetch();
}

Fetchは、あなたが慣れていることを正確には行いません。クエリが実行された後にデータをフェッチします。fetch_assoc結果オブジェクトから連想配列をフェッチします。

さらに、users.id = 1誰かがページをロードするたびにデータベースにクエリを実行することはお勧めできません。それをセットアップスクリプトに貼り付けます。そして、匿名ユーザーに不可能なパスワードを持たせます(別名、その代わりに$2y$13$<hash>Nope, not happenin'

また、データベースから直接HTMLにエコーします。サニタイズしない場合は、のようなユーザー名を作成<script src=""></script>して、最新のエクスプロイトを楽しむことができます。サニタイズ〜

更新:あなたのコードを読んだ後、私はあなたの問題を見つけました。

$stmt1 = $db->prepare("SELECT wins FROM users WHERE id = ?");
$stmt2 = $db->prepare("SELECT losses FROM users WHERE id = ?");
$stmt1->bind_param($_SESSION["id"]);
$stmt2->bind_param($_SESSION["id"]);
$stmt1->execute();
$stmt2->execute();
$row1 = $stmt1->fetch();
$row2 = $stmt2->fetch();

ここには3つの問題があります1

最初の問題は、特定の接続で一度に1つの準備呼び出ししか持てないことです。これは、ブロッキングAPI呼び出しであるためだと確信しています。私が間違っている場合は私を訂正してください。

2つ目は、呼び出しのタイプを指定しないことですbind_param。ここで指定するものにはすべてタイプを割り当てる必要があります。s=文字列、i=整数。

3つ目は、ここでは結果変数をまったくバインドしないことです。準備されたクエリを使用するときは、変数をバインドする必要があります。これは、このインスタンスの修正です。

if ($query = $db->prepare("SELECT wins, losses FROM users WHERE id = ?")) {
    $query->bind_param("s", $_SESSION["id"]);
    $query->execute();
    $query->bind_result($wins, $losses);
    if (!$query->fetch()) { // fetch one row from database.
        logout(); // or equiv.
    }
} else {
    if (DEBUG) {
        echo "Malformed SQL or In-use thread. SQL: <sql here>";
    } else {
        header("Location: /oops.php");
    }
}

1.または、複数のクエリでこれを行うことを数える場合は4。

于 2013-02-21T21:20:36.080 に答える
1

クエリに構文エラーがあり、クエリが失敗します。これは、$resultが結果オブジェクトではないことを意味します。電子メールを引用符で囲んでいないため、最初のクエリは失敗します。

SELECT id, username, password FROM users WHERE email = $email

する必要があります:

SELECT id, username, password FROM users WHERE email = '$email'

クエリの後に、次のようなものを入力する必要があります。

if ($result->errno!=0){
    echo $result->error;
    exit(0)
}
$row=$result->fetch_assoc();
//etc.
于 2013-02-21T21:10:10.627 に答える
0

@hirotoは正しいです。結果がない場合は、オブジェクトが存在しない可能性があります。そのため、非オブジェクトでメソッドを呼び出すと致命的なエラーが発生します。彼が述べたように、SQLクエリに問題があり、電子メールは文字列であるため引用符で囲む必要があります。そうしないと、MySQLはエラーで失敗します。

また、mysqliの結果オブジェクトにはfetch()のメソッドがないため、fetch_assoc()を提案しました。

結果を取得するには、結果オブジェクトを取得するように電子メールを引用する必要があります。データにアクセスするときは、次のいずれかのループを実行します。

$result = $db->query("SELECT id, username, password FROM users WHERE email = '$email'");
while($row = $result->fetch_assoc())
{
    print_r($row);
}

または、キーで直接データをプルします。

$result = $db->query("SELECT id, username, password FROM users WHERE email = '$email'");
$row = $result->fetch_assoc();
echo $row['username'];
于 2013-02-22T01:13:14.660 に答える