PHP PDO: Call to a member function prepare() & list? - php

Fatal error: Call to a member function prepare() on a non-object
Is what I am getting when I try to do:
$sql = $connect->prepare ("SELECT id, pwd, firstname, lastname, approved, user_level FROM users WHERE $user_cond AND banned = 0"); // SELECT
$sql->execute ();
$sql->setFetchMode(PDO::FETCH_ASSOC);
$num = $connect->rowCount();
Im holding on rewriting my system, taking out all mysql_* and make use of pdo instead.
This is what was before:
$result = mysql_query("SELECT `id`,`pwd`,`firstname`,`lastname`,`approved`,`user_level` FROM users WHERE
$user_cond
AND `banned` = '0'
") or die (mysql_error());
$num = mysql_num_rows($result);
What have I done wrong?
And with list() I have:
list($id,$pwd,$firstname,$lastname,$approved,$user_level) = mysql_fetch_row($result);
instead of mysql_fetch_row($result); what should I do in PDO?
My PDO object/connection:
try{
$connect = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset:UTF-8", DB_USER, DB_PASS, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}
catch(PDOException $pe)
{
die('Could connect to the database because: ' .$pe->getMessage());
}

Fatal error: Call to a member function
prepare() on a non-object
usually means that something failed and your variable is not what you expect it to be. $connection is probably false.
PDOStatement::fetch
list($id,$pwd,$firstname,$lastname,$approved,$user_level) = $sql->fetch();
Also call rowCount on the statement, not on the connection:
$sql->rowCount();

Since you using prepare, you should make the $cond a named parameter and then do this:
in this example the condition is just user_id, but you can have multiple conditions and multiple named parameters, just bind() each one the same way
$sth = $pdo->prepare ("SELECT id, pwd, firstname, lastname, approved, user_level FROM users WHERE user_id = :cond AND banned = 0");
$sth->bindParam(':cond', $some_user_id);
$sth->execute ();
$a = $sth->fetch( PDO::FETCH_ASSOC );
The $a will be your assiciate array, print_r($a) to see what's in it

Looks like a scope issue.
Are you assigning $connect within a function, class, namespace or are you running prepare in a function, class or namespace ?
if your assigning $connect within a function then that function should return the PDO Connection. I would introduce a static instance like so:
class Database extends PDO
{
private $instance = null;
public static function Instance()
{
if(self::$instance == null)
{
self::$instance = new Database();
}
return self::$instance;
}
private function __construct(){}
private function __connect()
{
try
{
parent::__construct("mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset:UTF-8", DB_USER, DB_PASS, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION))
}catch(PDOException $e)
{
die($e->getMessage());
}
}
}
then use like so:
$Database = Database::Instnace();
$Database->prepare("...");

The error is most likely due to the MySQL connection failing - therefor $connect is not a valid PDO object - so as the error says, you're trying to call a method on an object which doesn't support it. What does your connection handling code look like? Did you check if a connection was successfully created?

Related

How to return mysqli connect_error over 2 function in 2 classes PHP [duplicate]

This question already has an answer here:
What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must be of type mysqli_result and such
(1 answer)
Closed 2 years ago.
I have the dbc.inc.php file. inside of it there are connect function that connects me to the DB.
In the test.inc.php file i have the runQuery function inside of a "Test" class. The "Test" class extends from the "Dbc" class allocated in the dbc.inc.php file.
The runQuery($db, $sql) runs query. But if error happend or warning he is not showing the error. i belive that im having a syntax mistake.
For the testing interesst i have given the wrong fieldname in my $sql statment. The error is hapenning but is not showing.
dbc.inc.php
<?php
class Dbc{
private $serverName;
private $userName;
private $password;
protected function connect($dbName = NULL){
$this->serverName = "localhost";
$this->userName = "root";
$this->password = "";
$conn = new mysqli($this->serverName, $this->userName, $this->password, $dbName);
if (!$conn) {
die("<h3>Error Connecting to the Database.</h3><h4 style=\"color: red\">". $conn->connect_error . "</h4>");
} else {
return $conn;
}
}
}
?>
test.inc.php
<?php
require 'dbc.inc.php';
class Test extends Dbc{
function runQuery($db, $sql){
$query = mysqli_query($this->connect($db), $sql);
if (!$query) {
echo "no Query";
echo $this->connect($db)->connect_error;
return 0;
} else {
echo "Query EXEC";
return 1;
}
}
}
?>
The test code
$conn = new Test;
$conn->runQuery("tch_phn", "UPDATE `employee` SET `uiS`='Assad' WHERE `uid`='Assad' ");
The error is i have given a unknown field name (uiS has to be uid). How can i do this?
You don't need the Dbc class. It is not useful to you at all at its current state. The mysqli connection is always the same three lines of code and there is no point to add a class for it.
To connect to DB using mysqli use:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('localhost', 'user', 'pass', 'db_name');
$mysqli->set_charset('utf8mb4'); // always set the charset
Then you can write a class which will take the DB connection as a parameter in __construct().
class Test {
private \mysqli $db = null;
public function __construct(\mysqli $db) {
$this->db = $db;
}
function runQuery($sql) {
$query = $this->db->query($sql);
}
}
That's it. Although you really should try to create a more useful mysqli abstraction class, or even better, use PDO instead. If you want to write mysqli wrapper class you can start with the following idea (adjust to your needs):
class DBClass extends mysqli {
public function __construct($host = null, $username = null, $passwd = null, $dbname = null, $port = null, $socket = null) {
// Enable error reporting and call mysqli constructor
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
parent::__construct($host, $username, $passwd, $dbname, $port, $socket);
$this->set_charset('utf8mb4'); // always set the proper charset which should be utf8mb4 99.99% of the time
}
public function safeQuery(string $sql, array $params = []): ?array {
// Prepare statement:
$stmt = $this->prepare($sql);
// If the statement has parameters then bind them all now
if ($params) {
$stmt->bind_param(str_repeat("s", count($params)), ...$params);
}
// Execute it and get results if there are any
$stmt->execute();
if ($result = $stmt->get_result()) {
return $result->fetch_all(MYSQLI_BOTH);
}
// If the query was INSERT or UPDATE then return null
return null;
}
}
Then you can execute any SQL statement with a simple one line even when using mysqli.

Several mysqli queries with php singleton

I have a very common mysqli class to provide database connections for the rest of the application:
class IabDB extends mysqli {
private static $instance = null;
// db connection config vars
private $user = "xxx-lit";
private $pass = "xxx";
private $dbName = "xxx";
private $dbHost = "xxx";
private function __construct() {
parent::__construct($this->dbHost, $this->user, $this->pass, $this->dbName);
if (mysqli_connect_error()) {
exit('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
mysqli_set_charset($this, "utf8");
}
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
In my model I retrive data like this which works nicely:
$db = IabDB::getInstance();
$query = $db->query("SELECT status, username, email, id FROM " . $table);
$items = $query->fetch_all();
EDIT
But when I try to get another instance for another query I get the error message: Call to a member function fetch_all() on null.
Believe me: I tried it back and forth. Both queries are valid and both return a result if only either one of them is used. Just for the sake of completeness here is the second one with the model around:
class Model {
public static function getItems($table) {
$db = IabDB::getInstance();
$query = $db->query("SELECT * FROM lit_veranstaltungen");
$items = $query->fetch_all();
$db->close();
var_dump($items);
}
}
So it seems the second connection is disturbed somehow!?
Bonus question: from my knowledge the obviously now mostly laughed upon singleton pattern seems to be of good use for this purpose?
Any help and optionions are greatly appreciated!
Your code works for me, whatever number of instances I get:
$db = IabDB::getInstance();
$query = $db->query("SELECT name FROM users limit 1");
$items = $query->fetch_all();
var_export($items);
$db = IabDB::getInstance();
$query = $db->query("SELECT name FROM users limit 1,1");
$items = $query->fetch_all();
var_export($items);
returns
array ( 0 => array ( 0 => 'John', ), )
array ( 0 => array ( 0 => 'Mike', ), )
So I suppose there is an error with particular query you run. Therefore you need just better error reporting for your queries. Change your constructor to this
private function __construct() {
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
parent::__construct($this->dbHost, $this->user, $this->pass, $this->dbName);
$this->set_charset("utf8");
}
Then make sure your PHP is configured like this
error_reporting(E_ALL);
ini_set('display_errors',1);
and then run your code again.
It will either report an error or return an empty array. In the latter case it means that there are no rows in the database to match your second query conditions. E.g., for a code like this
$db = IabDB::getInstance();
$query = $db->query("SELECT name FROM users WHERE 1=0");
$items = $query->fetch_all();
var_export($items);
$db = IabDB::getInstance();
$query = $db->query("SELECT name FOrM users");
$items = $query->fetch_all();
var_export($items);
it will return an empty array for the first snippet and error for the second:
array ()
Fatal error: Uncaught exception 'mysqli_sql_exception' with message 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'users' at line 1'
Also, let me suggest you to add a function like this
public function query_params($query, $params, $types = NULL)
{
$statement = $this->prepare($query);
$types = $types ?: str_repeat('s', count($params));
$statement->bind_param($types, ...$params);
$statement->execute();
return $statement->get_result();
}
that will let you to use prepared statements as easily as with PDO:
$user = $db->query_params("SELECT * FROM users WHERE name = ?", ['Mike'])->fetch_assoc();
Regarding singleton, if you're using old style procedural PHP, then singleton is all right. If you're using OOP, then better implement a Dependency Injection based approach.
You cannot make singleton from class which extends mysqli (or PDO) since mysqli (and PDO) class constructor is public. You cannot override public parent's constructor and make it private in inherited child class! Try it and you will get the following error:
Fatal error: Access level to DataBase::__construct() must be public (as in class mysqli)
Try to use $query->close(); after you executed the query.
For this case, a singleton is not a bad idea. But more commonly, you have something like a "connection manager", which creates a mysqli object on first use, and then returns that object on consecutive calls, with the ability to have multiple connections to multiple databases or with differen users.
Something like this:
class DBConnection {
protected static $connections = array();
public static function getConnection($connection_name = 'default') {
if (!isset(static::$connections[$connection_name])) {
static::$connections[$connection_name] = // setup connection
// ... error handling and stuff
}
return static::$connections[$connection_name];
}
}
Btw.: In your constructor, I would use the mysqli object's properties for errorhandling:
http://php.net/manual/de/mysqli.connect-error.php
http://php.net/manual/de/mysqli.connect-errno.php
and
http://php.net/mysqli_set_charset

PHP: Assigning new PDO as object-attribute

I am trying to build a PDO connection to my MySQL database. This PDO is also being inherited by the child-classes of this class, where connection-specific functions are called from. When I call these connection-specific functions from the child-classes, I get an error.
So within the parent class, I have the following code:
...
protected $pdo;
public function __constructor() { //Check if public
try {
$pdo_local = new PDO(C_DB_PDODRIVER . ":host=" . C_DB_HOST . ";dbname=" . C_DB_DATABASE, C_DB_USERNAME, C_DB_PASSWORD);
$this->pdo = $pdo_local;
} catch (\PDOException $e) {
header("Location: error.html");
exit;
}
}
...
However, whenever I try to call the prepare statement of $this->pdo, I get a "Call to a member function prepare()" fatal error.
$query = "SELECT * FROM stacks WHERE id = :id LIMIT 1";
$stm = $this->pdo->prepare($query);
$para = array("id"=>$id); //where $id is the input parameter of the function
$stm->execute($para);
$result = $stm->fetch();
I have read that the PDO data-object is a null object, but I don't understand why? shouldn't $this->pdo = $pdo_local change that?
I am quite new to StackOverflow, so sorry if this question has flaws. Also, If you see any possible improvements in my code, please tell me!
Proper function name for constructor is __construct.

Trigger __construct function from another class

I've created a class which is named connect, it includes a construct function for my database:
construct.php
<?php
include('includes/constants.php');
class connect {
public $db;
function __construct() {
$this->db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME) or die();
}
}
?>
I'm trying to reach this class & function from within another class:
mysql.php
<?php
include_once('construct.php');
$connect = new connect();
class mysql {
function verifyLogInData($email, $password) {
$query = "SELECT * FROM users WHERE email = ? AND password = ? LIMIT 1";
if($stmt = $connect->db->prepare($query)) {
$stmt->bind_param('ss', $email, $password);
$stmt->execute();
if($stmt->fetch()) {
$stmt->close();
return true;
}
}
}
}
?>
However, it seems like I can't trigger the $connect object. What would be the right way to do this or should I trigger this function with another method?
Line which is giving me the error:
if($stmt = $connect->db->prepare($query)) {
Thanks in advance.
PS: Any advice on my code is very much appreciated :)
You need to understand variable scope. In this case, you can pass the instance into the method:
function verifyLogInData($email, $password, $connect) {...}
Though it might be better to inject it into the mysql class via the constructor, or indeed to merge the two into a single class - i dont see a good reson to have two when they are so closely coupled

mysql_connect vs mysqli_connect

i'm having a bit of an issue trying to use mysqli_connect the same way i use mysql_connect
this would be an example of my code:
QUERY.PHP
class classQuery{
public function __construct(){
require('conex/classConex.php');
require('conex/statement/classStatement.php');
$this->ObjConex = new classConex;
$this->ObjStatement = new classStatement;
}
public function Query($email){
$this->ObjConex->Conex();
$query='SELECT user_email from table where email='.mysql_real_escape_string($email).'';
$consulta = $this->ObjStatement->Select($query);
return $consulta;
}
CLASS STATEMENT
class classStatement{
public function __construct(){
$this->ObjConex = new classConex;
}
public function Select($query){
$query_execute = mysql_query($query);
while($row = mysql_fetch_row($query_execute)){
$consulta=htmlentities($row[0]);
}
return $consulta;
}
}
CLASS CONEX
class classConex{
public function Conex(){
require ('conex.php');
mysql_connect ($server,$dbuser,$dbpasswd) or die('Error de Conexión');
mysql_select_db($dbname);
}
}
Ok, now i want to use mysqli_connect instead of mysql_connect, according to php manual my new connect class should be something like this:
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'my_db');
now that my connection is an object i won't be able to execute my query from ClassStatement the same way i'm doing it, i have tested returning the object from the connect class but that means more code that i find redundant...is there a more elegant way to do this?
mysql_connect creates a global connection that you are depending on. This is already inelegant. You will have a lot more control (especially if you need to maintain multiple connections simultaneously) if you treat the connection as an object instance -- which is what mysqli forces you to do.
It's not redundant either .. it's just clear.
How about structuring your class like this:
class Database {
public function __construct ( $server, $dbuser, $dbpasswd, $dbname ) {
$this->dbhandle = new mysqli($server, $dbuser, $dbpasswd, $dbname);
}
public function Select ($query) {
$result = $this->dbhandle->query($query);
while ( $row = $result->fetch_row() ){
// Whatever you're doing here...
//$consulta = htmlentities($row[0]);
}
return $consulta;
}
}
So you could use it with this code:
class Query{
public function __construct(){
require('conex/classDatabase.php');
$this->Database = new Database($host, $user, $pass, $dbname);
}
public function Query ($email) {
$query = "SELECT user_email from table where email='".mysql_real_escape_string($email)."'";
$consulta = $this->Database->Select($query);
return $consulta;
}
}
I've included the object oriented syntax in my examples. Since you're using objects anyway, you'll probably get along with it.
Mysqli_connect is the newer version of mysql library.
Here I in mysqli stands for improved.
Few things have been introduced with Mysqli.
They are,
1.Prepared statements.
2.Object oriented interface.
3.Support for multiple statements.
4.Embedded server support.

Categories