Overview
I connect to a database in index.php, then import my classes.php file using require_once(). However, when connecting to the database, the database connection is undefined.
Code
index.php
$dbh = new PDO("mysql:host=$hostname;dbname=$dbname",$username,$password);
require_once("inc/classes.php");
/* ..... */
if($_POST["form"]=="login"){
//Retrieve values
$e = $_POST["email"];
$p = $_POST["password"];
//Data validation
if(!filter_var($e, FILTER_VALIDATE_EMAIL)||strlen($e)<3) $errors->addError("email", "Please enter a valid email address.");
if(strlen($p)<1) $errors->addError("password", "Please enter a valid password");
$errors->killErrors();
//Log user in
$user = new User($e);
if(!$user->login($p)) $errors->addError("form", "Incorrect username or password.");
$errors->killErrors();
exit("success");
}
inc/classes.php
class User
{
public $id, $email, $data;
public function __construct($e = null){
if(isLoggedIn()){
$stmt = $dbh->prepare("SELECT * FROM `users` WHERE `id`=? LIMIT 1");
$stmt->execute(array($_SESSION["userid"]));
$this->data = $stmt->fetch(PDO::FETCH_ASSOC);
} else $this->email = $e;
}
public function login($p){
//Perform database query for user
$stmt = $dbh->prepare("SELECT `id`, `password` FROM `users` WHERE `email`=? LIMIT 1");
$stmt->execute(array($this->email));
if($stmt->rowCount()<1) return false;
//Check password is correct
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if(!password_verify($p, $data["password"])) return false;
if(!$this->email) exit("User can only be logged in with an email address, not by User ID");
$this->id = $data["id"];
return $this->validate($this->id) ? true : false;
}
}
Output
Notice: Undefined variable: dbh in /var/www/html/foo/public_html/bar/inc/classes.php on line 80
Fatal error: Call to a member function prepare() on null in /var/www/html/foo/public_html/bar/inc/classes.php on line 80
Line 80 is:
$stmt = $dbh->prepare("SELECT `id`, `password` FROM `users` WHERE `email`=? LIMIT 1");
Question
How can I include the database connection in index.php and have the classes.php file accept that PDO object?
You have to make your connection global:
global $dbh;
Because of scope. Done carefully it is OK to use global variables. Many use it too haphazardly and have a tendency to want to globalize all of their variables. I personally do it within the function inside the class to eliminate ambiguity.
http://php.net/manual/en/language.variables.scope.php - as #JayBlanchard writes, you need to reference the connection handle as a global variable.
However, it's much cleaner to pass dependencies into your object. For instance, when instantiating your User, you can pass in the connection.
$user = new User($dbh, $e);
You can then set a private variable for the connection handle. This way, you can change the name of the variable in index.php, or change the way it's instantiated without your User class blowing up due to a change in a different file.
Related
So I am new to the OOP concept. I decided to make a call to my database, but in OO way. The error I am getting is:
Trying to get property 'num_rows' of non-object (at line 83 *reference to line 83)
I understand the error message, but fail to find out what is wrong regarding it. I have tried the following links, but unfortunately none of them have helped me really further, or I failed to understand what they meant.
Notice: Trying to get property 'num_rows' of non-object in line 35
Error - Trying to get property 'num_rows' of non-object
Get property num_rows of non-object
Trying to get property 'num_rows' of non-object
This is the reason I am knowingly making a duplicate question, hoping my problem would be something that has not (yet) been addressed in the other posts.
require 'connection.php';
//class DatabaseQueries handles all the queries required regarding CRUD.
class DatabaseQueries
{
//the SQL string
private $sql;
// The connection -> completegallery
private $conn;
public function __construct($conn)
{
$this->conn = $conn;
}
// function will check whether email already exists or not.
protected function getEmailExistance(string $email)
{
//create the SQL
$this->sql = $this->conn->prepare("SELECT * FROM userinfo WHERE email = ?");
//bind the parameter to it (preventing sql injection this way)
$this->sql->bind_param('s', $email);
// $result = the execution of the SQL.
$result = $this->sql->execute();
$resultCheck = $result->num_rows; //* line 83
var_dump($result); // returns boolean true.
var_dump($this->sql); // returns a mysqli stmt object
//check whether $resultCheck > 0
//if yes, that would mean the userName already exists.
if (!empty($result) && $resultCheck > 0)
{
exit('should show something');
} else
{
exit('always fails here');
}
}
} // ending class DatabaseQueries
How I call the class DatabaseQueries:
class Base extends DatabaseQueries
{
private $email;
private $userName;
private $name;
private $lastName;
private $pwd;
private $pwdConfirm;
// here is the code where I check and assign the user input to the variable $email etc.
//this method is for test purposes only and will be removed after the website is 'done'.
public function getEverything()
{
//link to check whether email is being used or not
$this->getEmailExistance($this->email);
}
}
How I invoke the objects etc.
$userInformation = new base($conn);
$userInformation->setEmail($_POST['registerEmail']);
//some other info, but not relevant to the problem.
I have already checked whether I misspelled anything, but this wasn't the case. The connection in connection.php has been declared correct aswell.
As mentioned in the comments, execute() does not return the result, you have to fetch() it. Here is the code that should allow you to do what you are asking.
// function will check whether email already exists or not.
protected function getEmailExistance(string $email)
{
//create the SQL
$this->sql = $this->conn->prepare("SELECT * FROM userinfo WHERE email = ?");
//bind the parameter to it (preventing sql injection this way)
$this->sql->bind_param('s', $email);
// $result = the execution of the SQL.
$this->sql->execute(); <---- No need for variable here, its boolean
$result = $this->sql->store_result(); <---- The result
$num_rows = $this->sql->num_rows; <---- This will contain your row count
if (!empty($result))
{
// fetch your results here
} else
{
exit('always fails here');
}
}
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.
I'm making a small CMS for some fun and practice. And I've come across this problem where I have to access a database multiple times in different functions. And the way I do it now by making a new prepared statement with the code and all to access the database in the function doesn't seem very convenient since the code is very repetitive and I'm using mostly the same code for each function. So how would I go about creating a class maybe or some functions that reduce the amount of code used in the functions that gather the information from that database? I currently use the following queries in SQL
SELECT
UPDATE
INSERT
DELETE
So mostly the basic ones. The code I'm using is basic PHP code where I'm using prepared statements to access my database like this:
// Create database connection
$con = db_connect();
// Initialize $error variable for errors
$error = "";
if ($stmt = $con->prepare("SELECT * FROM profiles WHERE username = ?")) {
// Bind the $username variable to the parameter in the query
$stmt->bind_param('s', $username);
// Execute the prepared query
$stmt->execute();
$stmt->store_result();
// Assign the data recieved from the database (if any)
$stmt->bind_result($data);
$stmt->fetch();
if ($stmt->num_rows == 1) {
if (!empty($stmt->error)) {
printf("Error: %s.\n", $stmt->error);
return false;
}
// Query successful
} else {
$error .= "User doesn't exist";
return false;
}
} else {
$error .= 'Could not connect to database';
return false;
}
To me this seems like pretty easy to use code, but when you have to paste it again and again in different functions, then it gets a bit frustrating.
You should use Dependency Injection.
By injecting the Database connection into a Profile's class, you have much more maneuverability to do what you please.
You can change that database to whatever you want (MongoDB, Cassandra, MySQL).
You are only declaring the connection once; which performs better and faster
Makes it easier to test and develop (echo & print_r & unit testing)
Handel exceptions in 1 place
Database is loosely couple with rest of code.
ex:
class Profile {
private $db = null;
public function __construct($db Database) {
$this->db = $db;
}
public function getProfile() {
//ish....
$this->db->query("SELECT * FROM profiles WHERE username = ?");
}
public function insert() {
...
}
public function update() {
...
}
public function delete() {
...
}
}
To access the database, I would do something like this and also implement what you have (prepared statements are great!):
class Database {
private $conn = null;
public function __construct($db Database) {
$this->conn = new PDO('mysql:host=localhost;dbname=myDatabase', $username, $password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $this->conn;
}
public function query($sql) {
try {
return $conn->query($sql);
} catch (Exception $e) {
echo $e->getMessage();
}
}
}
A very good explaination and tutorial can be found here: http://code.tutsplus.com/tutorials/dependency-injection-huh--net-26903
I am having an issue executing the below code. I get an error: Fatal error: Call to a member function prepare() on null in C:\xampp\htdocs... everytime I run it. It errors out right when it is about to query the database for some reason.
I am creating a function to check a username and password, and if it matches, log the user in and so forth. What I am trying to do is feed the outer function a username and a password, then pass those variables to the inner function (checkUser) to retrieve the user and password. Once I have those in an array, I want to compare to see if they match. If they do, then I want to continue on (I left the rest out for simplicity's sake). I don't know why I am getting the error I am getting, especially since it won't even run the 3rd line in the CheckUser without a fatal error.
This is homework, fyi, cards on the table. Just trying to get past this part. Thanks for any help.
function isValidUser($username, $password){
$checker = checkUser($username, $password);
if ($checker[user_email] == $username && $checker[user_pwd] == $password ) {
return TRUE;
}
}
function checkUser($username, $password) {
global $db;
$st = $db -> prepare('SELECT * FROM user WHERE user_email = ? and user_pwd = ?;');
$st -> bindParam(1, $username);
$st -> bindParam(2, $password);
$st -> execute();
return $st -> fetch(PDO::FETCH_ASSOC);
}
try this instead of global $db
$db = $GLOBALS['db'];
I have three errors
Warning: mysqli_stmt::fetch() expects exactly 0 parameters, 1 given in
/Volumes/shared/Digital/_Websites/_TEST/qpm/classes/mysql.php on line
20
Notice: Trying to get property of non-object in
/Volumes/shared/Digital/_Websites/_TEST/qpm/classes/mysql.php on line
23
Notice: Trying to get property of non-object in
/Volumes/shared/Digital/_Websites/_TEST/qpm/classes/mysql.php on line
23
Here is my code
<?php
require_once 'includes/constants.php';
class mysql{
private $conn;
function __construct(){
$this->conn = $conn = new MySQLi(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME)
or die ('There was an error in the connection');
}
function verify ($un, $pwd){
$username = $un;
$password = $pwd;
if ($sth = $this->conn->prepare("SELECT pass FROM User WHERE username = '".$un."' LIMIT 1")) {
$sth->execute();
$user = $sth->fetch(PDO::FETCH_OBJ);
// Hashing the password with its hash as the salt returns the same hash
if (crypt($password, $user->hash) == $user->hash) {
return true;
} else {
return false; }
}//end of if;
}//end of verify
}//enfd of class
Just trying to get pass and return true if its the same or false if not
Thanks
Like many, many, many other php users, you are confusing 2 totally different APIs - mysqli and PDO.
Please, choose one, namely PDO, and make your code consistent with it.
Here goes the code with all the useless stuff taken out,
yet with proper things, namely prepared statements, added:
function verify ($un, $pwd)
{
$sql = "SELECT pass FROM User WHERE username = ?"
$sth = $this->conn->prepare($sql);
$sth->execute(array($un));
$pass = $sth->fetchColumn();
return (crypt($pwd, $pass) == $pass);
}
but note that this function of verify should not be a method of mysql class