php PDO - 致命错误:在非对象上调用成员函数 fetch()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19017682/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 18:40:09  来源:igfitidea点击:

PDO - Fatal error: Call to a member function fetch() on a non-object

phpmysqlpdofetch

提问by user2693017

if I try to run the following PHP code, I get a

如果我尝试运行以下 PHP 代码,我会得到一个

Call to a member function fetch() on a non-object.

在非对象上调用成员函数 fetch()。

Do you know why? I use the same code on another site, where it works just fine.

你知道为什么吗?我在另一个网站上使用了相同的代码,在那里它工作得很好。

<?php
$username = ($_GET ['user']);
try {
    $dbh = new PDO("mysql:host=localhost;dbname=***", '***', '***');    
} catch (PDOException $e) {
    echo $e->getMessage();
}
$sth = $dbh->query( "SELECT user, captcha 
    FROM xf_captcha WHERE user='$username'" );
print_r($sth->fetch());
?>


Edit:

编辑:

$sth = $dbh->query( "SELECT username, user_state, last_activity, alerts_unread, conversations_unread, message_count 
    FROM xf_user WHERE username='$user'" );
$row = $sth->fetch();


Edit2:

编辑2:

Does this look safe, should I do more ?

这看起来安全吗,我应该做更多吗?

<?php
$username = ($_GET ['user']);
try {
    $dbh = new PDO("mysql:host=localhost;dbname=***", '***', '***');
} catch (PDOException $e) {
    echo $e->getMessage();
}
$sth = $dbh->prepare("SELECT username, captcha, timestamp 
    FROM xf_captcha 
    WHERE username = :username", array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $username));
print_r($sth->fetch());
?>

采纳答案by Fluffeh

Your code has the variable $usernamein the top part of your question, but you then have $userin the bottom section.

您的代码$username在问题的顶部有变量,但$user在底部有变量。

Are you perhaps meaning to use the same variable?

您可能打算使用相同的变量吗?

$username = ($_GET ['user']);
$sth = $dbh->query( "SELECT username, user_state, last_activity, alerts_unread, conversations_unread, message_count 
  FROM xf_user WHERE username='$user'" );
  //                           ^^ Should this ALSO be $username ?   
$row = $sth->fetch();

Edit: Okay, now you are just being cute with your PDO::ATTR_EMULATE_PREPARES. Observe this:

编辑:好的,现在你只是对你的PDO::ATTR_EMULATE_PREPARES. 观察这一点:

Database and table structure:

数据库和表结构:

Database changed
mysql> show tables
    -> ;
+----------------+
| Tables_in_prep |
+----------------+
| users          |
+----------------+
1 row in set (0.00 sec)

mysql> select * from users;
+----+---------+--------+
| id | userid  | pass   |
+----+---------+--------+
|  1 | Fluffeh | mypass |
+----+---------+--------+
1 row in set (0.00 sec)

And some PHP code that is copied from yours, with the added PDO attribute:

还有一些从您那里复制的 PHP 代码,并添加了 PDO 属性:

<?php
    //$username = ($_GET ['user']);
    $username="Fluffeh";

    $dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);

    $sth = $dbh->query( "SELECT userid, pass FROM users WHERE userid='$username'" );
    echo "Trying to use $username.\n";
    print_r($sth->fetch());
    echo "----------------------------------------\n\n";
?>

<?php
    //$username = ($_GET ['user']);
    $username="user2693017";

    $dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);

    $sth = $dbh->query( "SELECT userid, pass FROM users WHERE userid='$username'" );
    echo "Trying to use $username.\n";
    print_r($sth->fetch());
    echo "----------------------------------------\n\n";
?>

<?php
    //$username = ($_GET ['user']);
    $username="Oh my' or 1=1 or 'm=m";

    $dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);

    $sth = $dbh->query( "SELECT userid, pass FROM users WHERE userid='$username'" );
    echo "Trying to use $username.\n";
    print_r($sth->fetch());
    echo "----------------------------------------\n\n";
?>

<?php
    //$username = ($_GET ['user']);
    $username="(select id from users limit 1)";

    $dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);

    $sth = $dbh->query( "SELECT userid, pass FROM users WHERE id='$username'" );
    echo "Trying to use $username.\n";
    print_r($sth->fetch());
    echo "----------------------------------------\n\n";
?>

<?php
    //$username = ($_GET ['user']);
    // Changed this one to be a non-string, you might be checking an ID instead.
    $username="(select id from users limit 1)";

    $dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);

    $sth = $dbh->query( "SELECT userid, pass FROM users WHERE id=$username" );
    echo "Trying to use $username.\n";
    print_r($sth->fetch());
    echo "----------------------------------------\n\n";
?>

<?php
    //$username = ($_GET ['user']);
    $username="bob'; drop table users; \  
    ";
    // This one is tricker to do in PHP code. I could easily enter this into a text field however.

    $dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);

    //$sth = $dbh->query( "SELECT userid, pass FROM users WHERE id='$username'" );
    echo "Trying to use $username.\n";
    print_r($sth->fetch());
    echo "----------------------------------------\n\n";
?>

And the output:

和输出:

    Trying to use Fluffeh.
stdClass Object
(
    [userid] => Fluffeh
    [pass] => mypass
)
----------------------------------------


    Trying to use user2693017.
----------------------------------------


    Trying to use Oh my' or 1=1 or 'm=m.
stdClass Object
(
    [userid] => Fluffeh
    [pass] => mypass
)
----------------------------------------


    Trying to use (select id from users limit 1).
----------------------------------------


    Trying to use (select id from users limit 1).
stdClass Object
(
    [userid] => Fluffeh
    [pass] => mypass
)
----------------------------------------


    Trying to use bob'; drop table users; \  
        .
----------------------------------------

Oh, the reason I left the last one till LAST is this output now in my database:

哦,我把最后一个留到最后一个的原因是现在我的数据库中的这个输出:

mysql> show tables;
Empty set (0.00 sec)

Yes, that's right, I just dropped a table. Let me say that again, I had a select statement, and with a little trickery I entered in a value that ANYONE with half a brain and some malicious intent could do into a text field, and DROPPED YOUR TABLE.

是的,没错,我刚丢了一张桌子。让我再说一遍,我有一个 select 语句,我用一点技巧输入了一个值,任何有半脑和恶意的人都可以在文本字段中输入该值,然后删除您的表格。

Now, granted, if you are setting things up properly, you might well set up a different user for the select statements, and only grant them selectrights from your database, to stop this sort of thing happening - but lets be honest... you aren't are you?

现在,当然,如果您设置正确,您很可能会为 select 语句设置一个不同的用户,并且只select从您的数据库授予他们权限,以阻止此类事情的发生 - 但老实说......不是吗?

Clearly setting that emulation is not enough. Seriously, now PLEASE do go read that answer, use prepared statements and use params if you want to be secure in your code.

显然设置该仿真是不够的。说真的,现在请务必阅读该答案,如果您想确保代码安全,请使用准备好的语句并使用参数。

回答by Orion

Where is your Execute statement being called? Is this also inside your ->query? If not think of using the following for also a better query build up.:

你的 Execute 语句在哪里被调用?这也在你的里面->query吗?如果不考虑使用以下内容来构建更好的查询。:

<?php
            $username = ($_GET['user']);
            try {
                $dbh = new PDO("mysql:host=localhost;dbname=***", '***', '***');    
            } catch (PDOException $e) {
                echo $e->getMessage();
            }
            $statement = "SELECT user, captcha FROM xf_captcha WHERE user=:username";
            //If you have query as a method(Which I don't think so but if you can change "prepare" to your "query"
            $sth = $dbh->prepare($statement);
            $sth->execute(array(":username" => $username));
            $row = $sth->fetch(PDO::FETCH_ASSOC);
    ?>

In the execute parentheses you can use an array to fill the parameter :usernamefor the variable $username

在执行括号中,您可以使用数组来填充:username变量的参数$username

I think looking into PDO Class examples might also be good for a better understanding of PDO and methods(You can also refer to the PHP PDO Manual)

我认为查看 PDO 类示例也可能有助于更好地理解 PDO 和方法(您也可以参考 PHP PDO 手册)

回答by a coder

It happens when the table doesn't exist also. make sure it actually exists, and isn't just a holder in the database due to hard drive errors.

当表不存在时也会发生这种情况。确保它确实存在,并且不只是由于硬盘驱动器错误而在数据库中的一个持有者。

When that happens I suggest you recreate the database/table if phpMyAdmin gets an error when trying to read it "manually".

发生这种情况时,如果 phpMyAdmin 在尝试“手动”读取时出错,我建议您重新创建数据库/表。