php function not returning class object - php

I have a DB class that I've created several functions in to return various values. One of the functions returns (or is supposed to) a "user" class object that represents a logged in user for the application.
class user {
public $guid = '';
public $fname = '';
public $lname = '';
public function __construct() {}
public function print_option() {
return "<option value='$this->guid'>$this->name</option>";
}
}
In the DB class I have the following 2 functions:
public function get_user($uid) {
$sql = '';
$usr = new user();
$sql = "SELECT guid, fname, lname FROM ms.users WHERE guid=?";
if($sth = $this->conn->prepare($sql)) {
$sth->bind_param('s', $uid);
if($sth->execute()) {
$sth->bind_result($usr->guid, $usr->fname, $usr->lname);
$sth->fetch();
print_r($usr); // PRINTS OUT CORRECTLY
return $usr;
}
else {return null;}
}
else {return null;}
}
public function get_practice_user_list($pguid) {
$ret = '';
$sql = "SELECT user_guid FROM ms.perm WHERE p_guid=?";
if($sth = $this->conn->prepare($sql)) {
$sth->bind_param('s', $pguid);
if($sth->execute()) {
$usr = new user();
$guid = '';
$sth->bind_result($guid);
while($sth->fetch()) {
print_r($guid); // PRINTS GUID correctly
$usr = $this->get_user($guid);
print_r($usr); // PRINTS NOTHING object is null so prints "error" two lines later.
if($usr != null) $ret .= $usr->print_option();
else print "error";
}
return $ret;
}
else {return null;}
}
else {return null;}
}
I'm just not understanding why the "user" object is not returning in this instance. Others calls to the get_user function work just fine and return the user class object pertaining to that user.
TIA

I guess you guid may be an integer so
$sth->bind_param('s', $uid);
bind_param's first param should be 'i' not 's';
http://www.php.net/manual/en/mysqli-stmt.bind-param.php

The problem was with the query. Since the code was just looping through one query (get_practice_user_list), then calling the get_user function and attempting a second query MySQL came back with an error of out of sync message. When I looked that up, I was able to fix it by doing a fetch_all on the first query then looping through that array to get the users.

Related

Assign object attributes from the result of prepared statement

I'm wanting to create a new instance of my Class and assign it's attributes the values that are returned. The reason for this is I'm creating a series of methods inheriting from the calling class, as opposed to using static methods which I already had working.
Example of what I'm using currently:
public static function findById($id) {
$id = self::escapeParam($id);
$idVal = is_int($id) ? "i" : "s";
$sql = "SELECT * FROM ".static::$db_table." WHERE id = ? LIMIT 1";
return static::findByQuery($sql,$idVal,$id);
}
public static function findByQuery($sql,$bindChar = '',$bindVal = '') {
try {
$callingClass = get_called_class();
$object = new $callingClass;
$statement = Database::$connection->prepare($sql);
if(!empty($bindChar)) :
$statement->bind_param($bindChar, $bindVal);
endif;
if($statement->execute()) :
$result = $statement->get_result();
$object = $result->fetch_object();
endif;
$statement->close();
if(!empty($object)) :
return $object;
endif;
} catch(Exception $e) {
}
}
What I tried was writing an instantiation method that creates a new instance of my class, and then assign each attribute of the object the value it returns from an array from a tutorial I did. However, the tutorial was fairly outdated and didn't use any new syntax or binding, so I was trying to rework this.
Example from the tutorial below:
public static function find_by_id($id) {
global $database;
$the_result_array = static::find_by_query("SELECT * FROM " . static::$db_table . " WHERE id = $id LIMIT 1");
return !empty($the_result_array) ? array_shift($the_result_array) : false;
}
public static function find_by_query($sql) {
global $database;
$result_set = $database->query($sql);
$the_object_array = array();
while($row = mysqli_fetch_array($result_set)) {
$the_object_array[] = static::instantation($row);
}
return $the_object_array;
}
public static function instantation($the_record){
$calling_class = get_called_class();
$the_object = new $calling_class;
foreach ($the_record as $the_attribute => $value) {
if($the_object->has_the_attribute($the_attribute)) {
$the_object->$the_attribute = $value;
}
}
return $the_object;
}
private function has_the_attribute($the_attribute) {
return property_exists($this, $the_attribute);
}
What I was trying to do from the tutorial, was to return my result as an array using a while, and then assigning a variable by passing the built array into the static::instantation() method, but it doesn't seem to ever be working correctly, as any public functions I create in my calling class (Admin for example) aren't called after as they don't exist due to the Class not being instantiated.
mysqli_result::fetch_object() accepts the class name as the first argument. You can pass the class name as an argument to that method and get the instance of the model. I am not sure why you have that much code but consider my example which I wrote based on your own code:
<?php
class Model
{
public static function findByQuery(string $sql, ?string $bindChar = null, ?string $bindVal = null): ?static
{
$statement = Database::$connection->prepare($sql);
if ($bindChar) :
$statement->bind_param($bindChar, $bindVal);
endif;
$statement->execute();
$result = $statement->get_result();
return $result->fetch_object(static::class);
}
}
class User extends Model
{
private $id;
}
class Database
{
public static mysqli $connection;
}
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
Database::$connection = new mysqli('localhost', 'user', 'password', 'test');
$user = User::findByQuery('SELECT ? as id', 's', 'Dharman');
var_dump($user);
The output from that example is:
object(User)#4 (1) {
["id":"User":private]=>
string(7) "Dharman"
}
As you can see, the code created an instance of the class using late-static binding and it also assigned the value to a private property, which you can't do otherwise.
P.S. My example is a little bit tidier. I added parameter typing and removed a lot of unnecessary code. In particular, I remove empty try-catch which is a terrible practice.
I have now got this working, although I feel this is probably not the best way of doing it.
I'm primarily front end so please comment if there are improvements or best practices.
public static function findByQuery($sql,$bindChar = '',$bindVal = '') {
try {
$statement = Database::$connection->prepare($sql);
if(!empty($bindChar)) :
$statement->bind_param("$bindChar", $bindVal);
endif;
if($statement->execute()) :
$result = $statement->get_result();
$output = $result->fetch_object();
endif;
$statement->close();
if(!empty($output)) :
$class = get_called_class();
$object = new $class;
foreach(get_object_vars($output) as $key => $value) :
$object->$key = $value;
endforeach;
endif;
if(!empty($object)) :
return $object;
endif;
} catch(Exception $e) {
}
}
My initial thoughts were declaring an object and then I thought that the PHP fetch_object call would have just assigned my object it's properties after initiating the Class but that wasn't the case.
So what I've done is that if the statement is successful and a results object is created, I then get the object properties and values with the get_object_vars() command, and then loop through these as a key value pair, assigning each attribute it's returned value.
I can confirm this works as I can now run $admin->remove() from my removal script, as opposed to what I was having to do before which was Admin::remove($id);

Building a Login model using PHP PDO and MVC

could use help with a simple code with both PHP and SQL (PDO) :)
Trying to access a table, withdraw 1 row from 1 column with specific details using MVC and then verifying said info, building it and then entering that info into Session storage so that I can validate what "role" and "user" is present at a certain time.
That's my controller
<?php
class PagesController {
public function home() {
$first_name = 'Qwerty';
$last_name = 'Qwerty';
require_once('views/pages/home.php');
}
public $admin_model;
public function __construct() {
$this->admin_model = new Admin();
}
public function login() {
session_start();
$log = $this->admin_model->LoginModel();
if($log == true){
$admin= $this->admin_model->findAdmin($_POST['user'],$_POST['pass']);
if($admin == true){
$_SESSION['user'] = $admin['user'];
print_r($_SESSION);
}
require_once('views/pages/login.php');
}else if($log == false){
echo "There is no existing account with that information. Please try a different account.";
require_once('views/pages/home.php');
}
}
?>
And this is my Admin Model.
<?php
require_once 'connection.php';
class Admin{
public $name;
public $role;
public $phone;
public $email;
public $password;
public $img;
public $id;
public function __construct() {
}
public function LoginModel(){
if(isset($_POST['user'])&&($_POST['pass'])){
$name= $_POST['user'];
$password=$_POST['pass'];
}
else{
$name='NULL#NULL';
$password='NULL';
}
$db = Db::getInstance();
$sql = $db->prepare('SELECT * FROM `admin` WHERE "Name" = "'.$name.'" AND Password = ' . $password .' ');
$sql->execute();
$result = $sql->setFetchMode(PDO::FETCH_ASSOC);
if($result >= 1){
return true;
}else{
return false;
}
}
public function findAdmin($name, $password){
$db = Db::getInstance();
$sql = $db->prepare('SELECT * FROM `admin` WHERE "Name" = "'.$name.'" AND Password = ' . $password .' ');
$sql->execute();
$result = $sql->setFetchMode(PDO::FETCH_ASSOC);
if($result > 0){
return $result;
}
}
}
Now, the first one, the Login() model works, BUT it doesn't matter what $_POST['user'] or $_POST['pass'] I input it always works :/... so it seems my SQL query always returns a true (i'm inputting the same into as found in the table, username "admin" and password "12345" but no matter what information I put in? it works. which is odd..
Second of all I want to "Find" the admin after login in and putting that info into a session that I can verify on every view... any help?...
I think your specific problem is that you're using the return of setFetchMode() as an indicator of whether or not rows were found by the execution. Since its return value is TRUE simply by virtue of it succeeding in setting the fetch mode, you're probably always going to see TRUE returned.
You probably need to do fetchAll() and count the records in the array, if all you want to do as verify that at least one row was returned.

PHP Using Object to Retrieve DB data

I am wondering if someone could help me. I am new to PHP OOP and would like some guidance with using objects.
I am making a login script and the functions I mention below are all from the class file.
Class USER{
public function userLogin($username,$password)
{
$statusY = "Y";
$stmt = $this->connection->prepare("SELECT * FROM tbl_users WHERE user_name=:userName LIMIT 1");
$stmt ->execute(array(":userName"=>$username));
$row = $stmt ->fetch(PDO::FETCH_ASSOC);
if($stmt->rowCount() == 1)
{
$this->_user = $row; // Assign user details
$_SESSION['userSession'] = $row['user_id'];
}
}
public function getUser()
{
return $this->_user;
}
Ok so I have the getUser() function and then assign $this->_user = $row so I can retrieve the user info from the database. Now I want to acheive a couple of things from this but not sure how to go about it.
How would I go about calling $row['user_id'] in another function within the same class?
So basically
public function test()
{
$user_id = $this->_user(user_id);
$username = $this->_user(username);
}
How would I do this correctly?
Also if I want to call the information in a page such as the User Homepage.
$user_home = new USER();
$userID = $user_home->getUser(user_id);
echo $userID;
If anyone could give me some guidance as to how I can move forward with this I would greatly appreciate it. Thanks
Let's start with a basic statement regarding method and class naming: I wouldn't repeat the class' topic over and over again (in the above case "user"), instead just remove it from the method name:
class User
{
private $info= array();
private $authenticated= FALSE;
public function login ($username, $password)
{
// do your stuff
...
// set in case that user name and password have been found
$this->info= $row;
$this->authenticated= TRUE;
}
public function isAuthenticated ()
{
return $this->authenticated;
}
/**
* returns all info from a given user
*/
public function get ()
{
return $this->info;
}
/**
* returns a single field
*/
public function getField ($fieldName) {
if (isset($this->info[$fieldName]) {
return $this->info[$fieldName];
} else {
return FALSE;
}
}
}
Use the getField(FIELD) method to return only a single element of the user's row and get() to return all values.
$user= new User();
$user->login ($username, $password);
if ($user->isAuthenticated()) {
$home= $user->getField('home');
print sprintf('%s\'s home is %s', $username, $home);
}
It's also advisable to create a class for the user database table (i.e. class UserModel) and another one handling user functions (i.e. class UserAuth) which uses the UserModel class. This makes exchanging the underlying authentication source more easy.
Class USER
{
public $_user;
public function userLogin($username,$password)
{
$statusY = "Y";
$stmt = $this->connection->prepare("SELECT * FROM tbl_users WHERE user_name=:userName LIMIT 1");
$stmt ->execute(array(":userName"=>$username));
$row = $stmt ->fetch(PDO::FETCH_ASSOC);
if($stmt->rowCount() == 1)
{
$this->_user = $row; // Assign user details
$_SESSION['userSession'] = $row['user_id'];
}
}
public function getUser()
{
return $this->_user;
}
}

PHP Construct Usage

I'm learning how to use classes properly... I'm looking at usercake and most of it makes sense, however I'm not sure what the __construct function is doing. I understand it gets called when you create the class... i.e. $loggedInUser = new loggedInUser();
What does the stuff below do and why do I need it?
function __construct($user, $display, $title, $pass, $email)
{
//Used for display only
$this->displayname = $display;
//Sanitize
$this->clean_email = sanitize($email);
$this->clean_password = trim($pass);
$this->username = sanitize($user);
$this->title = sanitize($title);
if(usernameExists($this->username))
{
$this->username_taken = true;
}
else if(displayNameExists($this->displayname))
{
$this->displayname_taken = true;
}
else if(emailExists($this->clean_email))
{
$this->email_taken = true;
}
else
{
//No problems have been found.
$this->status = true;
}
}
Edit: Here is how the class gets called:
$loggedInUser = new loggedInUser();
$loggedInUser->email = $userdetails["email"];
$loggedInUser->user_id = $userdetails["id"];
$loggedInUser->hash_pw = $userdetails["password"];
$loggedInUser->title = $userdetails["title"];
$loggedInUser->displayname = $userdetails["display_name"];
$loggedInUser->username = $userdetails["user_name"];
$loggedInUser->alerts = array();
It is the constructor function. When you create an instance of that class your constructor function is run.
For example, with your constructor (I don't know your class name).
$class = new MyClass("jdoe", "John Doe", "Standard User", "Passw0rd!","jdoe#example.com");`
This will create a new MyClass and store it in $class.
As for its purpose, it lets you initialize the object to a starting state of some kind. You can populate properties, set default values, or just do nothing. It is really application specific.
EDIT (in response to OP's edit)
I would really suggest keeping your object properties either protected or private and use setter/getters to access that data. You are giving public access to your objects properties, which isn't bad, but it can lead to accidentally changing something you didn't mean to change. Maybe you should consider something like this:
<?php
class LoggedInUser
{
private $id;
private $username;
private $password;
private $displayname;
private $email;
private $title;
public function __construct($id, $username, $password, $displayname, $email, $title)
{
$this->setID($id);
$this->setUsername($username);
$this->setPassword($password);
$this->setDisplayName($displayname);
$this->setEmail($email);
$this->title($title);
}
public function sanitize($var)
{
//Sanitize $var and then...
return $var;
}
public function setID($num)
{
$this->id = $this->sanitize($num);
}
public function setUsername($string)
{
$this->username = $this->sanitize($string);
}
//Keep adding other "set" methods.
}
?>
Then to use this you would do something like:
$loggedin = new LoggedInUser( "arg1", "arg2", "etc..." );
Now your object is setup with the starting state. If you need to change a property later you can always do:
$loggedin->setTitle("Correct Title");
Make sure you create functions to return your properties as well. In the example above your properties are private so a call to $loggedin->title would generate an error in PHP
// Set construct function which will run when your class is called
function __construct($user, $display, $title, $pass, $email)
{
// Sets display name
$this->displayname = $display;
// Sanitizing user inputted data (See SQL injection/XSS attacks)
$this->clean_email = sanitize($email);
$this->clean_password = trim($pass);
$this->username = sanitize($user);
$this->title = sanitize($title);
// Check if any duplicates of the user inputted data exist already in the database
// If any of these checks return true, the status wont be set to true, and further code wont be ran
if(usernameExists($this->username))
{
$this->username_taken = true;
}
else if(displayNameExists($this->displayname))
{
$this->displayname_taken = true;
}
else if(emailExists($this->clean_email))
{
$this->email_taken = true;
}
else
{
// No duplicate information has been found, set status and continue registration
$this->status = true;
}
}
You need it because initialize the object you create.

PHP OOP unable to edit class properties

New to PHP and especially OOP.
I have a class User.php which I am using in login.php.
$vars = $user->login($email, $pass)
At the moment I am calling the login method as the above, eventually I am going to call an if statment to validate, etc.
At the moment however, I am trying to connect to the DB, pull some information out and add that information to the properties in my class. I can pull the information out (verified by var_dumps of the objects in method login() (vardump of $results), yet for some reason with my current code I cannot update my class properties.
Here is my code
User.php
<?php
class User {
public $id, $password, $first_name, $last_name;
private $user_level;
protected static $db_fields = array('id', 'first_name', 'last_name', 'pass');
protected static $table_name="users";
public function login($email, $pass) {
global $database;
$sql = "SELECT user_id, first_name, last_name, user_level FROM users WHERE (email='$email' AND pass=SHA1('$pass')) AND active IS NULL LIMIT 1";
$results = self::find_by_sql($sql);
if (!empty($results)) {
$this->setuservars($results);
return array_shift($results);
} else {
return false;
}
// return !empty($results) ? array_shift($results) : false;
}
private function setuservars($uservariables) {
$this->id = $uservariables->id;
$this->first_name = $uservariables->first_name;
$this->last_name = $uservariables->last_name;
$this->user_level = $uservariables->user_level;
}
public static function find_by_sql($sql="") {
global $database;
$results_array = $database->query($sql);
$object_array = array();
while ($row = $results_array->fetch_assoc()) {
$object_array[] = self::instantiate($row);
}
return $object_array;
}
public function mysqli_array_escape($arg1){
global $database;
foreach ($arg1 as $key => $value) {
$arg1[$key] = $database->real_escape_string($value);
}
return $arg1;
}
private static function instantiate($record) {
// Could check that $record exists and is an array
$object = new self;
foreach($record as $attribute=>$value){
if($object->has_attribute($attribute)) {
$object->$attribute = $value;
}
}
return $object;
}
private function has_attribute($attribute) {
return array_key_exists($attribute, $this->attributes());
}
protected function attributes() {
// return an array of attribute names and their values
$attributes = array();
foreach(self::$db_fields as $field) {
if(property_exists($this, $field)) {
$attributes[$field] = $this->$field;
}
}
return $attributes;
}
}
$user = new User();
?>
and here is my login.php (I have edited the if statement with to verify the user logged in successfully, i have replaced with "if (1 == 1) {" statement just to help with debugging code.
if (isset($_POST['submitted'])) {
$postdata = $user->mysqli_array_escape($_POST);
//var_dump($user->results);
if (((!isset($_POST['email'])) || ($_POST['email']) == '') || (!isset($_POST['pass']) || ($_POST['pass']) == '') ) {
//error handling eventually
} else {
$email = $_POST['email'];
$pass = $_POST['pass'];
$vars = $user->login($email, $pass);
echo $vars->first_name;
if (1 == 1) {
echo "you have successfully logged in";
var_dump($user->id);
} else {
echo "not logged in";
}
}
}
Oh and the current error I am receiving is "An error occurred in script 'F:\internet\www\htdocs\blissoop\classes\User.php' on line 26: Trying to get property of non-object
Date/Time: 4-13-2012 05:01:09"
I have resolved this issue with help from this question
here was the code that helped : Get value from Multidimentional Array containing an Object.
I have +1'd the answer which helped.
foreach ($array as $item) {
$userId = $item->user_id;
//do something with the userId for this item
}
I had to loop through the array to be able to get the object's properties.

Categories