understanding a error in php membership system - php

I am building a membership system in php using sessions, functions and MySQL querys,
I have come across a problem or a error that I do not understand the meaning and how to correct it.
any help on this matter would be greatly appreciated.
Error reads
Fatal error: Call to a member function error() on a non-object in /home/ob219/public_html/membership/index.php on line 6
code for index
$user = DB::getInstance()->get('users', array('username', '=', 'ben'));
if($user->error()) {
echo 'No user';
} else {
echo 'OK!';
}
db.php function
public function action($action, $table, $where = array()) {
if(count($where) === 3) {
$operators = array('=', '>', '<', '>=', '<=');
$field = $where[0];
$operator = $where[1];
$value = $where[2];
if(in_array($operator, $operators)) {
$sql = "{$action} FROM {$table} WHERE {$field} {$operator} ?";
if(!$this->query($sql, array($value))->error()) {
return $this;
}
}
}
return false;
}
public function get($table, $where) {
return $this->action('SELECT *', $table, $where);
}
public function delete($table, $where) {
return $this->action('DELETE', $table, $where);
}
public function error() {
return $this->_error;
}

was a simple error, I had Users as table name, and in index.php I had users.
Solution
<?php
require_once 'core/init.php';
$user = DB::getInstance()->get('Users', array('username', '=', 'ben'));
if((!$user->count())) {
echo 'No user';
} else {
echo 'OK!';
}

Related

PHP OOP boolean error

I have got the following error:
Fatal error: Uncaught Error: Call to a member function count() on boolean in C:\xampp\htdocs\pianocourse101\index.php:5 Stack trace: #0 {main} thrown in C:\xampp\htdocs\pianocourse101\index.php on line 5
I have been wondering whether is the error part of my function count in my db.php or from index.php? Here is my code:
db.php
<?php
class DB {
private static $_instance = null;
private $_pdo,
$_query,
$_error = false,
$_results,
$_count = 0;
private function __construct() {
try {
$this->_pdo = new PDO('mysql:host='.Config::get('mysql/host').';dbname='.Config::get('mysql/db'), Config::get('mysql/username'),Config::get('mysql/password'));
} catch(PDOException $e) {
die($e->getMessage());
}
}
public static function getInstance() {
if(!isset(self::$_instance)) {
self::$_instance = new DB();
}
return self::$_instance;
}
public function query($sql, $params = array()) {
$this->_error = false;
// set the error to false so that we are not returning a previous error
if($this->_query = $this->_pdo->prepare($sql)) {
// check to see if query has been prepared properly
$x=1;
if(count($params)) { // check to see if need to bind
anything
foreach($params as $param) {
$this->_query->bindValue($x, $param);
$x++;
}
}
if($this->_query->execute()) {
$this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
$this->_count = $this->_query->rowCount(); // to query a
database securely by binding parameters and preventing sql
injections
} else {
$this->_error = true;
}
}
return $this; // return the currenct object we are working with
}
public function action($action, $table, $where = array()) {
if(count($where) === 3) {
$operators = array('=', '>', '<', '>=', '<=');
$field = $where[0];
$operator = $where[1];
$value = $where[2];
if(in_array($operator, $operators)) {
$sql = "{$action} * FROM {$table} WHERE {$field} {$operator} ?";
if(!$this->query($sql, array($value))->error()) {
return $this;
}// to check to see if operator is inside the operators .... We do a ? so that we can bind the value on
}
}
return false;
}
public function get($table, $where){
return $this->action('SELECT *', $table, $where);
}
public function delete($table, $where) {
return $this->action('DELETE ', $table, $where);
}
public function error() {
return $this->_error;
}
public function count() {
return $this->_count;
}
}
index.php
<?php
require_once 'core/init.php';
$user = DB::getInstance()->get('users', array('username', '=', 'alex'));
if (!$user->count()) {
echo 'No user';
} else {
echo 'OK!';
}
Your get() method will always fail since it's generating an invalid SQL query.
Explanation
If we take your request:
$user = DB::getInstance()->get('users', array('username', '=', 'alex'));
and break it up to see what happens (this is the same thing as the above):
// This will work and return an instance of DB
$db = DB::getInstance();
// Will always fail and return false, since the get() method fails
$user = $db->get('users', array('username', '=', 'alex'));
// Since user is false (a boolean), it doesn't have any methods
$user->count()
So, why does it fail? Let's look in your DB class.
Let's start with the get() method:
public function get($table, $where){
// This is calling an internal method called "action()" passing three values
return $this->action('SELECT *', $table, $where);
}
and where it fails, the action() method:
public function action($action, $table, $where = array()) {
if(count($where) === 3) {
$operators = array('=', '>', '<', '>=', '<=');
$field = $where[0];
$operator = $where[1];
$value = $where[2];
if(in_array($operator, $operators)) {
// The get() method passed 'SELECT *' to this method, so the below string will be
// "SELECT * * FROM users WHERE username = ?"
// (hint: it's the double * * that's invalid) .
$sql = "{$action} * FROM {$table} WHERE {$field} {$operator} ?";
if(!$this->query($sql, array($value))->error()) {
// Since the query fails, it will never come here
return $this;
}
}
}
// Since the query fails (is invalid), this is what it will return
return false;
}
Solution
A quick fix would be to change the action() method from:
$sql = "{$action} * FROM {$table} WHERE {$field} {$operator} ?"
to
$sql = "{$action} FROM {$table} WHERE {$field} {$operator} ?"
As I've mentioned in comments, you should look into proper error handling for PDO. Or better yet, use some tried and tested db library.
You mentioned that you are new to PHP and are going through some tutorial, the would recommend learning the basics step by step.

Why isn't my foreach loop displaying my mysql data?

I am trying to extend the function of this tutorial on youtube, and I have run into some issues. Here is the particular chunk of code I am currently struggling with:
public function listProjects() {
$projects = DB::getInstance()->get('projects', array('projectStatus', '=', 'active'));
if($projects->count()) {
echo 'This query senses rows, but returns data it does not';
foreach($projects as $project) {
echo $project->projectName;
}
}
}
This is a method of my "Project" class, and it uses methods from the DB class, with relevant code here:
private function __construct() {
try {
$this->_pdo = new PDO('mysql:host=' . Config::get('mysql/host') . ';dbname=' . Config::get('mysql/db'), Config::get('mysql/username'), Config::get('mysql/password'));
} catch(PDOException $e){
die($e->getMessage());
}
}
public static function getInstance() {
if(!isset(self::$_instance)){
self::$_instance = new DB();
}
return self::$_instance;
}
public function query($sql, $params = array()){
$this->_error = false;
if($this->_query = $this->_pdo->prepare($sql)) {
$x = 1;
if(count($params)) {
foreach($params as $param) {
$this->_query->bindValue($x, $param);
$x++;
}
}
if($this->_query->execute()) {
$this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
$this->_count = $this->_query->rowCount();
} else {
$this->_error = true;
}
}
return $this;
}
public function action($action, $table, $where = array()) {
if(count($where) === 3) {
$operators = array('=', '>', '<', '>=', '<=');
$field = $where[0];
$operator = $where[1];
$value = $where[2];
if(in_array($operator, $operators)) {
$sql = "{$action} FROM {$table} WHERE {$field} {$operator} ?";
if(!$this->query($sql, array($value))->error()) {
return $this;
}
}
} return $this;
}
public function get($table, $where) {
return $this->action('SELECT *', $table, $where);
}
So in my index.php, I write this code:
$projectList = new Project;
$projectList->listProjects();
To try and retrieve all of my "projects" stored in the database. I put the "This query senses rows, but returns data it does not" echo in order to determine if rows were being counted, which they are, because that statement is echoed, but my foreach statement is not working correctly. The field in the projects table that I am trying to access is projectName. I would eventually like to display all relevant project info, but I'm sure I could figure that out once I get it to display anything from the database.
This:
foreach($projects as $project) {
echo $project->projectName;
}
should be:
foreach($projects as $project) {
echo $projects->projectName;
}

Results are repeating in DB::getInstance

I am new to php and I am trying to develop a class. I am connected to sqlsrv and the connection is fine. Its when I run the query the results are repeating almost like it's in a loop. I can not find the problem and I was hoping an extra pair of eyes can help. Any help is appreciated!
class DB{
private static $_instance = null;
private $_connection,
$_query,
$_error = false,
$_results,
$_count = 0;
private function __construct(){
$mssqlInfo = array( "Database"=>"db");
$mssqlServer = "server";
$this->_connection = sqlsrv_connect($mssqlServer, $mssqlInfo);
if($this->_connection === false ) {
echo '<h2>Unable to connect to database</h2><br/>';
die( print_r(sqlsrv_errors(), true));
}else{
//echo 'Connected';
}
}
public static function getInstance(){
if(!isset(self::$_instance)){
self::$_instance = new DB();
}
return self::$_instance;
}
public function query($sql, $params = array()){
$this->_error = false;
$options = array( "Scrollable" => SQLSRV_CURSOR_STATIC );
$this->_query = sqlsrv_query($this->_connection, $sql, $params,$options);
if($this->_query){
$this->_results = sqlsrv_fetch_object($this->_query);
$this->_count = sqlsrv_num_rows($this->_query);
}else{
$this->_error = true;
echo 'Error in statement execution.\n';
die( print_r( sqlsrv_errors(), true));
}
return $this;
}
public function action($action, $table, $where = array()){
if(count($where) === 3){
$operators = array('=', '>', '<', '>=', '<=');
$field = $where[0];
$operator = $where[1];
$value = $where[2];
if(in_array($operator, $operators)){
$sql = "{$action} FROM {$table} WHERE {$field} {$operator} (?)";
if(!$this->query($sql, array($value))->error()){
return $this;
}
}
}
return false;
}
public function get($table, $where){
return $this->action('SELECT *', $table, $where);
}
public function delete($table, $where){
return $this->action('DELETE', $table, $where);
}
public function results(){
return $this->_results;
}
public function first(){
return $this->results()[0];
}
public function error(){
return $this->_error;
}
public function count(){
return $this->_count;
}
}
here is the instance on the index page that I am using to test my functions and to retrieve the query.
require_once 'core/init.php';
$users = DB::getInstance()->query("SELECT * FROM users");
$user = DB::getInstance()->get('users', array('username', '=', 'mike'));
if(!$user->count()){
echo 'No user';
}else{
$obj = $users->results();
foreach($obj as $users){
echo $users->username;
echo '<br/>';
}
}
I forgot to included the table.
CREATE TABLE [dbo].[users](
[id] [int] IDENTITY(1,1) NOT NULL,
[username] [varchar](20) NOT NULL,
[password] [varchar](64) NOT NULL,
[salt] [varchar](32) NOT NULL,
[name] [varchar](50) NOT NULL,
[joined] [datetime] NOT NULL,
[group] [int] NOT NULL,
CONSTRAINT [PK_users] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
You fetch only one row of the results in function query() and save it to member _results:
$this->_results = sqlsrv_fetch_object($this->_query);
Then you use function results() in a while loop. results() returns an object saved in member _results which will never change. That's why you got an endless loop.
Solution for your problem:
Change
public function query($sql, $params = array()){
[...]
$this->_query = sqlsrv_query($this->_connection, $sql, $params,$options);
if($this->_query){
$this->_results = sqlsrv_fetch_object($this->_query);
$this->_count = sqlsrv_num_rows($this->_query);
[...]
to
public function query($sql, $params = array()){
[...]
$this->_query = $sql;
$this->_results = sqlsrv_query($this->_connection, $sql, $params,$options);
if($this->_query){
$this->_count = sqlsrv_num_rows($this->_query);
[...]
And change
public function results(){
return $this->_results;
}
to
public function results(){
return sqlsrv_fetch_object($this->_results);
}
It looks like you're setting $obj to $user->results() in your while loop, so it's always true and therefore never stops.
Just change it to a foreach().
$obj = $user->results();
foreach ($obj as $user) {
echo $user->username;
echo '<br/>';
}

Database not reading current sessions

I have the following code and database table that at one point worked perfect together. If a user was on my site, the database would show those users.
I have the session class conjoint with an ini file that I require on every page of my site, so the session is always running.
I have the same code on another site of mine and this is where I brought the code over from, but one time a user was on it and it seems like the database table froze and up to this day, it still shows that user having a session, but if I go on it or anyone else, it doesn't show.
Does anyone see anything in the following that could be wrong?
CREATE TABLE `groups` (
`id` int(11) NOT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`permissions` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Session class
class Session {
public static function exists($name) {
return (isset($_SESSION[$name])) ? true : false;
}
public static function put($name, $value) {
return $_SESSION[$name] = $value;
}
public static function get($name) {
return $_SESSION[$name];
}
public static function delete($name) {
if(self::exists($name)) {
unset($_SESSION[$name]);
}
}
public static function flash($name, $string = '') {
if(self::exists($name)) {
$session = self::get($name);
self::delete($name);
return $session;
} else {
self::put($name, $string);
}
}
}
Here's part of my db class..
public function action($action, $table, $where = array()){
if(count($where) === 3){
$operators = array('=', '>', '<', '>=', '<=');
$field = $where[0];
$operator = $where[1];
$value = $where[2];
if(in_array($operator, $operators)) {
$sql = "{$action} FROM {$table} WHERE {$field} {$operator} ?";
if(!$this->query($sql, array($value))->error()) {
return $this;
}
}
}
return false;
}
public function get($table, $where){
return $this->action('SELECT *', $table, $where);
}
public function delete($table, $where){
return $this->action('DELETE', $table, $where);
}
public function insert($table, $fields = array()) {
$keys = array_keys($fields);
$values = '';
$x = 1;
foreach($fields as $field) {
$values .= '?';
if($x < count($fields)) {
$values .= ', ';
}
$x++;
}
$sql = "INSERT INTO {$table} (`" . implode('`, `', $keys) . "`) Values ({$values})";
return ! $this-> query($sql, $fields)->error();
}
public function update($table, $id, $fields) {
$set = '';
$x = 1;
foreach($fields as $name => $value) {
$set .= "{$name} = ?";
if($x < count($fields)) {
$set .= ', ';
}
$x++;
}
$sql = "UPDATE {$table} SET {$set} WHERE id = {$id}";
return ! $this-> query($sql, $fields)->error();
}
public function results() {
return $this->_results;
}
public function first() {
return $this->results()[0];
}
public function error() {
return $this->_error;
}
public function errorMessage() {
return $this->_errmsg;
}
public function count(){
return $this->_count;
}
}

Proper way to access database in PHP classes

My limited PHP knowledge is rather old. When I used to create websites I always had a config.php file which contained some defines and a $_DB global variable. Then in every function_xyz.php file I included this config file.
Now I want to finally move on and use classes. But I can't figure out a proper way to have access to mysql in functions of my classes without inclusion of the so called config.php file on top of each file.
Imagine I have a class called User.php:
class User {
private $firstName;
private $familyName;
private $emailAddress;
public function __construct($username, $password) {
//check if user with name and pass exist in DB
// stuff....
//If user exist, populate member variables
$this->emailAddress = ...
}
public function getEmail(){
return $this->emailAddress;
}
}
I know it is not the best example or practice...but how can I have a global MySQL access in all my classes without being required to have the config file included.
What is the best practice nowadays?
Make a global Instance:
//db.php include once
class DB {
#bind connenction in it
}
#make instance
$db = new DB($config);#use for User Instances
and then:
class User {
private $db;
private $firstName;
private $familyName;
private $emailAddress;
public function __construct($db) {
$this->db=$db;
}
public function validate($username, $password,$db) {
//check if user with name and pass exist in DB
//If user exist, populate member variables
$this->emailAddress = ...
}
public function getEmail(){
return $this->emailAddress;
}
}
$user = new User($db);
Is one way.
But you telling to less about how you want to use the classes.
I would go with PHPAcademy's login/register tutorial. He have DB class that handles almost anything you need. Here is sample of his code, slightly modified by me, but all credits to Alex Garrett.
<?php
class DB {
private static $_instance = null;
private $_pdo,
$_query,
$_error = false,
$_results,
$_count = 0;
private function __construct() {
try {
$this->_pdo = new PDO('mysql:host=' . Config::get('mysql/host') . ';dbname=' . Config::get('mysql/db'), Config::get('mysql/username'), Config::get('mysql/password'));
} catch(PDOException $e) {
die($e->getMessage());
}
}
public static function getInstance() {
if(!isset(self::$_instance)) {
self::$_instance = new DB();
}
return self::$_instance;
}
public function query($sql, $params = array()) {
$this->_error = false;
if($this->_query = $this->_pdo->prepare($sql)) {
$x = 1;
if(count($params)) {
foreach($params as $param) {
if (is_int($param)) {
$this->_query->bindValue($x, $param, PDO::PARAM_INT);
} else {
$this->_query->bindValue($x, $param);
}
$x++;
}
}
if($this->_query->execute()) {
$this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
$this->_count = $this->_query->rowCount();
}
else {
$this->_error = true;
print_r($this->_query->errorInfo());
}
}
return $this;
}
public function action($action, $table, $where = array()) {
if(count($where) === 3){
$operators = array('=', '>', '<', '>=', '<=', '!=');
$field = $where[0];
$operator = $where[1];
$value = $where[2];
if(in_array($operator, $operators)) {
$sql = "{$action} FROM {$table} WHERE {$field} {$operator} ?";
if(!$this->query($sql, array($value))->error()) {
return $this;
}
}
} else if (count($where) === 0) {
$sql = "{$action} FROM {$table}";
if(!$this->query($sql)->error()) {
return $this;
}
}
return false;
}
public function get($table, $where) {
return $this->action('SELECT *', $table, $where);
}
public function delete($table, $where) {
return $this->action('DELETE', $table, $where);
}
public function getAll($table) {
return $this->action('SELECT *', $table);
}
public function first() {
return $this->results()[0];
}
public function last() {
$i = count($this->results()) - 1;
return $this->results()[$i];
}
public function insert($table, $fields = array()) {
if(count($fields)) {
$keys = array_keys($fields);
$values = '';
$x = 1;
foreach ($fields as $field) {
$values .= '?';
if($x < count($fields)) {
$values .= ', ';
}
$x++;
}
$sql = "INSERT INTO {$table} (`" . implode('` , `', $keys) . "`) VALUES({$values})";
if (!$this->query($sql, $fields)->error()) {
return true;
}
}
return false;
}
public function update($table, $where, $parametar, $fields) {
$set = '';
$x = 1;
foreach ($fields as $name => $value) {
$set .= "{$name} = ?";
if ($x < count($fields)) {
$set .= ', ';
}
$x++;
}
if (is_int($parametar)) {
$sql = "UPDATE {$table} SET {$set} WHERE {$where} = {$parametar}";
} else {
$sql = "UPDATE {$table} SET {$set} WHERE {$where} = '{$parametar}'";
}
if (!$this->query($sql, $fields)->error()) {
return true;
}
return false;
}
public function results() {
return $this->_results;
}
public function error() {
return $this->_error;
}
public function count() {
return $this->_count;
}
}
Then you can query database like DB::getInstance()->getAll('tableName')->results();. Change DB credentials in __construct, or watch his videos (which I recomend).

Categories