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

I'm getting the error:
Call to a member function fetch() on a non-object
The line this refers to is:
$getProjectIdResult = $stmt->fetch();
Now, I think from this error that there must be something wrong with my database query, since the documentation says PDO query returns false on failure. I'm having trouble identifying what is causing the issue.
I've tried wrapping the fetch in a try/catch, with
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
However the catch isn't triggered and I just get the original fatal error so I haven't been able to get a more specific error.
classes.php
class Query extends Connection {
public function getProjectID($surveyID) {
$query_getProjectID = "SELECT projectID FROM test WHERE surveyID = :surveyID";
$query_getProjectID_params = array(
':surveyID' => $surveyID
);
try {
$stmt = $this->db->prepare($query_getProjectID);
$stmt = $stmt->execute($query_getProjectID_params);
}
catch (PDOException $ex) {
die("Failed to get project ID: " . $ex->getMessage());
}
$getProjectIdResult = $stmt->fetch();
$getProjectID = $getProjectIdResult['projectID'];
return $getProjectID;
}
}
test.php
include_once("includes/classes.php");
include_once("includes/functions.php");
// Bind $_GET data
// localhost/panel/test.php?surveyID=3&status=1&respondentID=666
// Expected result: 111
$surveyID = sanitise($_GET['surveyID']);
$status = sanitise($_GET['status']);
$respondentID = sanitise($_GET['respondentID']);
$con = new Connection();
$query = new Query();
$query->getProjectID($surveyID);
$con->closeConnection();
I've ruled out the sanitise function causing an issue by testing with and without it.
I apologise as I know this is probably just another amateur making another amateur mistake judging by how many posts there are by the same title.

When you call
$stmt = $stmt->execute($query_getProjectID_params);
You assign the return-value of execute() to $stmt, overwriting the variable, making it a boolean instead of an object. When you continue, $stmt no longer holds the PDOStatement object, but is now a boolean.
The solution is simply to remove the overwrite of your object, like this (remove $stmt = in front).
$stmt->execute($query_getProjectID_params);
http://php.net/pdostatement.execute

Related

Classes and methods with PDO, and retrieving the data

I'm new to OOP programming, and I'm really lost with this what the title says. When I try to put the query in a class and in another file, I get errors in a file called Main.php and don't even know what to do to fix them:
Notice: Undefined variable: sth in Select.php on line 10
Fatal error: Cannot access empty property in Select.php on line 10
If I put the select in Connection.php, it returns the rows just fine, but with classes, I get those.
Here's my code:
Connection.php:
<?php
$hostname = 'localhost';
$username = 'user';
$password = 'pass';
function connectDB ($hostname, $username, $password){
$dbh = new PDO("mysql:host=$hostname;dbname=database", $username, $password);
return $dbh;
}
$dbh = connectDB ($hostname, $username, $password);
echo 'Connected to database <br/>';
Select.php:
<?php require_once 'Connection.php';
class Select {
public function select() {
$sql= "select * from table limit 10; <br/>";
echo $sql;
$select = $dbh->query($sql)->fetchall(PDO::FETCH_ASSOC);
foreach($this->$sth as $row){
echo $row['column']."<br/>";
}
}
}
The question is, how can I print the result from the query (for example from main.php, which has an autoloader), and why do I get those errors, when on a single file, they work just fine?
Edit:
<?php
$test = new Select($dbh);
echo $test->select();
?>
Besides the fixes in the replies, I included Connection.php into the main.php, changed the echo in Select.php to return and it works perfectly now. Adding this in case someone ever gets as lost as me.
You do not want to iterate over the query, but the result of that query. So this probably is what you are looking for:
<?php
class Select {
public function select() {
$sql= 'select * from table limit 10';
$select = $dbh->query($sql)->fetchall(PDO::FETCH_ASSOC);
foreach($select as $row){
echo $row['column']."<br/>";
}
}
}
And you also need to take care that the $dbh object is actually present inside that method. Either inject it into the object or specify it as method argument. So your full class will probably look something like that:
<?php
class Select {
private $dbh;
public function __construct($dbh) {
$this->dbh = $dbh;
}
public function select() {
$sql= 'select * from table limit 10';
$select = $this->dbh->query($sql)->fetchall(PDO::FETCH_ASSOC);
foreach($select as $row){
echo $row['column']."<br/>";
}
}
}
And you instantiate the object like that:
$selectObj = new Select($dbh);
Some general warning, though: Using PDO's fetchall() method is convenient, but carries a huge risk: it means that the full result set has to be copied into an array inside the php script. For bigger results that may lead to issues with memory usage (scripts getting terminated for security reasons). Often it is the better approach to use a while loop over a single row fetched from the result set in each iteration.

Fatal error: Call to a member function prepare() on boolean in

I red several questioins, but no one helped.
Fatal error: Call to a member function bind_param() on boolean in -> nope.
Fatal error: Call to a member function prepare() on null -> nope.
Fatal error: Call to a member function count() on boolean -> nope.
Fatal error Call to a member function prepare() on null -> nope.
fatal error call to a member function prepare() on resource -> nope.
Error: Call to a member function prepare() on a non-object -> nope. I am done..
I am using PHP5 and mySql with PDO:
Connection and Select works fine, but the Insert didnt want to work.
That's my function:
function AddNewUser($nickname, $email)
{
ini_set('display_errors', 1); //DELETE ME
ini_set('expose_php', 1); //DELETE ME
$pdo = EstablishDBCon();
echo "Subscribe user..<br/>";
$sql = "INSERT INTO db.table (nickname, email, insertdate, updatedate) VALUES (:nickname, :email, :insertdate, :updatedate)";
try {
$stmt = $pdo->prepare($sql); //Error at this line
//id?
$stmt->bindParam(':nickname', $nickname, PDO::PARAM_STR);
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
$stmt->bindParam(':insertdate', date("Y-m-d H:i:s"), PDO::PARAM_STR);
$stmt->bindParam(':updatedate', null, PDO::PARAM_NULL);
$stmt->exeute();
CloseDBCon($pdo);
echo "Subscribed!<br/>";
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
}
The DB pattern is:
id (int not null auto_inc) | nickname (varchar not null) | email (varchar not null) | insertdate (datetime) | updatedate (datetime)
I am new to php and I do not understand that type of error.
I marked the line inside the code, where the error is thrown:
$stmt = $pdo->prepare($sql); //Error at this line
Can someone help me?
Thanks in advance!
//EDIT:
Connection aka db_connection.php:
<?php
echo 'Establishing MySQL Connection<br/>';
$pdo = null;
$dsn = 'mysql: host=xx; dbname=xx';
$dbUser = 'xx';
$pw = 'xx';
try {
$pdo = new PDO($dsn, $dbUser, $pw);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo 'Connection established.<br/>';
}
catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
return $pdo;
?>
Here is the EstablishDBCon function:
function EstablishDBCon()
{
$pdo = include_once 'db_connection.php';
return $pdo;
}
The best way to reuse functions is to put it inside of the include file, then include it at the top of each file you'll need it. So inside of your db_connection.php, create your function:
function EstablishDBCon()
{
$pdo = false;
try{
// Put your PDO creation here
} catch (Exception $e) {
// Logging here is a good idea
}
return $pdo;
}
Now you can use that function wherever you need it. Make sure you always make sure $pdo !== false before you use it, to make sure your connection hasn't failed.
The problem is in the function EstablishDBCon(), which expects the include_once statement to return a value as if the contents of the included file are a function.
function EstablishDBCon()
{
$pdo = include_once 'db_connection.php';
return $pdo;
}
But that's not how include_once works here:
if the code from a file has already been included, it will not be included again, and include_once returns TRUE.
That's why you end up with TRUE (a boolean) in your $pdo variable.
In any event, this kind of construction makes your code really hard to follow.
I recommend only using include and friends to combine self-contained PHP functions together, or to embed parts of HTML pages in one another.
Call to a member function on boolean in this case means that $pdo is not an object, it's a boolean. So it's likely that EstablishDBCon() is returning either a true on success or false otherwise, as opposed to a database resource. Double-check the docs on that function. Here's a link to some relevant documentation on PDO that you'll need.

I'm struggling to upgrade login script with PDO

I have a custom query() function in my functions. file. I created a login.php file, but when I make a SQL query, the query() function returns a PDO object, instead of an associative array I desire. I need help to pass parameters to be bound to a stored procedure/prepared statement.
The following is the login.php file:
<?php
// configuration
require("../../includes/config.php");
// if form was submitted
if ($_SERVER["REQUEST_METHOD"] == "POST")
{
// validate submission
if (empty($_POST["username"]))
{
adminapologize("You must provide your username.");
}
else if (empty($_POST["password"]))
{
adminapologize("You must provide your password.");
}
$username = $_POST["username"];
// query database for user
$sql = "SELECT * FROM admin WHERE username = '$username'";
$result = query($sql,array($username));
//var_dump($result);
//exit;
if($sql != false)
{
if($result->rowCount() == 0)
{
printf("No admin yet.");
}
// if we found user, check password
if($result->rowCount() == 1)
{
// first (and only) row
$row = $result->fetch();
// compare hash of user's input against hash that's in database
if ($_POST["username"] == $row["username"] && crypt($_POST["password"], $row["hash"]) == $row["hash"])
{
// remember that user is now logged in by storing user's ID in session
$_SESSION["admin_id"] = $row["admin_id"];
// redirect to admin home
redirect("index.php");
}
}
}
else
{
// else apologize
adminapologize("Invalid username and/or password.");
}
}
else
{
// else render form
adminrender("login_form.php", ["title" => "Admin Log In"]);
}
?>
Be advised that the config.php includes the functions.php file. And the following is the portion of the functions.php file:
/**
* Executes SQL statement, possibly with parameters, returning
* a pdo statement object on success, handling and halting execution on error.
*/
function query($sql, $parameters = null)
{
static $pdo; // define the var as static so that it will persist between function calls
try
{
// if no db connection, make one
if (!isset($pdo))
{
// connect to database
// you should set the character encoding for the connection
$pdo = new PDO("mysql:dbname=" . DB_NAME . ";host=" . DB_SERVER, DB_USERNAME, DB_PASSWORD);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // set the error mode to exceptions
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); // turn emulated prepares off
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC); // set default fetch mode to assoc so that you don't have to explicitly list the fetch mode every place
}
if(empty($parameters))
{
// no bound inputs
$stmt = $pdo->query($sql);
} else {
// has bound inputs
$stmt = $pdo->prepare($sql);
// you should use explicit bindValue() statements to bind any inputs, instead of supplying them as a parameter to the ->execute() method. the comments posted in your thread lists the reasons why.
$stmt->execute($parameters);
}
}
catch (Exception $e)
{
// all errors with the connection, query, prepare, and execute will be handled here
// you should also use the line, file, and backtrace information to produce a detailed error message
// if the error is due to a query, you should also include the $sql statement as part of the error message
// if $pdo ($handle in your code) is set, it means that the connection was successful and the error is due to a query. you can use this to include the $sql in the error message.
trigger_error($e->getMessage(), E_USER_ERROR);
//exit; // note: E_USER_ERROR causes an exit, so you don't need an exit; here.
}
return $stmt; // if the query ran without any errors, return the pdo statement object to the calling code
}
Your help would be much appreciated.
You've got an excellent function, no need to spoil it.
the query() function returns a PDO object, instead of an associative array I desire.
It's actually an object that you want to be returned. As for the array, you can simply get it by chaining fetch to the call:
$result = query($sql,array($username))->fetch(); // voila!
Look, with function returning an object you can get not only single row but dozens different kinds of results. Like single column value with fetchColumn() or many formats supported by fetchAll(). Not to mention you can get numRows() from the object while from array you can't.
With this function in its current form you can run DML queries as well, while returning fetch it will end up with error. Returning an object is a really really cool thing!
The only bad thing about your function is that you are catching an exception and converting it into an error manually, while PHP is already doing it for you.
Just get rid of this try catch block and you will have exactly the same (actually, even better) error reporting.
// all errors with the connection, query, prepare, and execute will be handled here
// you should also use the line, file, and backtrace information to produce a detailed error message
// if the error is due to a query, you should also include the $sql statement as part of the error message
// if $pdo ($handle in your code) is set, it means that the connection was successful and the error is due to a query. you can use this to include the $sql in the error message.
ALL these things PHP is already doing for you, if you simply don't catch an exception.
(save for storing an $sql variable which is not needed actually, as you can find a query following a back trace)
As of the code, it should be five times shorter:
$sql = "SELECT * FROM admin WHERE username = ?";
$row = query($sql,array($username))->fetch();
if($row && crypt($_POST["password"], $row["hash"]) == $row["hash"])
{
// remember that user is now logged in by storing user's ID in session
$_SESSION["admin_id"] = $row["admin_id"];
// redirect to admin home
redirect("index.php");
//this is essential as otherwise anyone will be able to proceed with this page
exit;
}
BTW, I just noticed that you are using your function wrong, sending $username right into the query. I fixed it too.
Edit according to #Your Common Sense's answer who's absolutley right:
Call your function 'query' and do directly on that result a fetch.
For example as mentioned in the comments below:
$rows = query($sql, $params)->fetch();
If you want rows as associative array do
$rows = query($sql, $params)->fetch(PDO::FETCH_ASSOC);
This explicitly returns an associative array.
You have to fetch the result after executing.
$stmt->execute($parameters);
return $stmt->fetch(PDO::FETCH_ASSOC);
This should return an associative array.
See also: http://php.net/manual/de/pdostatement.fetch.php
/**
* Executes SQL statement, possibly with parameters, returning
* a pdo statement object on success, handling and halting execution on error.
*/
function query($sql, $parameters = null)
{
static $pdo; // define the var as static so that it will persist between function calls
$return = false;
try {
// if no db connection, make one
if (!isset($pdo)) {
// connect to database
// you should set the character encoding for the connection
$pdo = new PDO("mysql:dbname=" . DB_NAME . ";host=" . DB_SERVER, DB_USERNAME, DB_PASSWORD);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // set the error mode to exceptions
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); // turn emulated prepares off
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC); // set default fetch mode to assoc so that you don't have to explicitly list the fetch mode every place
}
if(empty($parameters)){
// no bound inputs
$stmt = $pdo->query($sql);
} else {
// has bound inputs
$stmt = $pdo->prepare($sql);
// you should use explicit bindValue() statements to bind any inputs, instead of supplying them as a parameter to the ->execute() method. the comments posted in your thread lists the reasons why.
$stmt->execute($parameters);
$return = $stmt->fetch(PDO::FETCH_ASSOC);
}
} catch (Exception $e)
{
// all errors with the connection, query, prepare, and execute will be handled here
// you should also use the line, file, and backtrace information to produce a detailed error message
// if the error is due to a query, you should also include the $sql statement as part of the error message
// if $pdo ($handle in your code) is set, it means that the connection was successful and the error is due to a query. you can use this to include the $sql in the error message.
trigger_error($e->getMessage(), E_USER_ERROR);
//exit; // note: E_USER_ERROR causes an exit, so you don't need an exit; here.
}
return $return; // if the query ran without any errors, return the pdo statement object to the calling code

Fatal Error with fetch_assoc inside a function

I truly need your help. I have seen answers and even followed advice as previously posted but NO SOLUTIONS SHOW how to use fetch associated array using PREPARED STATEMENTS so I am not trying to submit an already answered question. I have followed suggestions to others questions but I am still getting:
Fatal error: Call to a member function fetch_assoc() on a non-object in /xxx/xxxxxx.php on line 75
I am showing you the old code using MySQL and how I have changed it to MySQLi using prepared statements, but I am still getting the same Fatal Error. Can someone please help me, I am going crazy and I truly need to find out what I am doing wrong. Thanks for your help.
//*******************************************************************
// OLD CODE:
// Called by: $theme=$log->get_theme();
//*******************************************************************
class redirect
{
function __construct()
{
}
function get_theme()
{
$rs=mysql_query("select * from theme where status='yes'");
if(mysql_num_rows($rs)>0)
{
$data=mysql_fetch_array($rs);
return $data['theme_name'];
}
}
}
//*********************************************************************
// OLD CODE:
// Called by: $theme=$log->get_theme($cn);
//*********************************************************************
class redirect
{
public $cn;
function __construct()
{
}
function get_theme($cn)
{
$themeStatus = 'yes';
if ($stmt = $cn->prepare("SELECT * FROM theme WHERE status = ? "))
{
$stmt->bind_param("s", $themeStatus);
$result = $stmt->execute();
$stmt->store_result();
if ($stmt->num_rows >= "1")
{
$data = $result->fetch_assoc(); // ERROR LINE
return $data['theme_name'];
}
}
else
{
echo "Failed to execute prepared statement: " . mysqli_connect_error();
}
}
}
The mysqli_stmt::execute method returns only bool by definition. So calling $result->any_method_name() will fail because $result is a boolean value.
To get the values from a prepared statement using the MySQLi library you bind your target variables with $stmt->bind_result(...) and then use $stmt->fetch() in a while loop to get the result of your query in your bound variables. And after that you switch from MySQLi to PDO because it has a better API regarding this…

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

Feeling a little stupid to ask such a question, but this code block is driving me crazy.
function __construct() {
$db = new db();
$this->db = $db->pdo;
}
function getEmployeeDetails() {
$eid = $this->db->quote($this->eid);
try {
$sql = $this->db->query("
SELECT email, cnumber
FROM employees
WHERE EID = $eid
");
$r = $sql->fetch();
$this->email = $r[0];
$this->cnumber = $r[1];
}
catch (PDOException $e) {
throw new Exception("failed");
}
}
It doesn't throw an exception but fails inside the try block - "Call to a member function fetch() on a non-object".
var_dump of the statement object returns 'false'. Why?
I've tried running the query independently, inside MySql. It returns 1 row.
It's hard to tell whether you have done this, but PDO doesn't throw exceptions by default, except on connection failures. You have to specifically add this:
$this->db = $db->pdo;
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Without this, errors that occur during the query will cause ->query() to return false and that's obviously not an object that will have the ->fetch() method. You can also specify this attribute as part of the constructor call.
Also, you could use prepared statements instead of using ->quote():
$stmt = $this->db->prepare("SELECT email, cnumber
FROM employees
WHERE EID = ?");
$stmt->execute(array($this->eid));
$r = $stmt->fetch();

Categories