I have a problem here on PHP OOP. I try to do something that I always do in .NET - pass the whole object to the function. Unfortunately, the script didn't appear to work and when I try to debug (using Netbeans) it stopped here:
$ud = new userdetails($fullname, $email, $contact, $username, $password, $password2);
Can somebody tell me what did I do wrongly? Thanks in advance!
My script:
<?php
include 'class/registration.php';
$fullname = $_POST['fullname'];
$email = $_POST['email'];
$contact = $_POST['contact'];
$username = $_POST['username'];
$password = $_POST['password'];
$password2 = $_POST['password2'];
$ud = new userdetails($fullname, $email, $contact, $username, $password, $password2);
if (registration::checkEmptyField($ud)==true){
$error = "Please don't leave any field empty";
}
userdetail class:
<?php
class userdetails {
protected $_fullname;
protected $_email;
protected $_contact;
protected $_username;
protected $_password;
protected $_password2;
public function __construct($fullname,$email,$contact,$username,$password,$password2) {
$this->_fullname = $fullname;
$this->_email = $email;
$this->_contact = $contact;
$this->_username = $username;
$this->_password = $password;
$this->_password2 = $password2;
}
public function get_fullname() {
return $this->_fullname;
}
public function get_email() {
return $this->_email;
}
public function get_contact() {
return $this->_contact;
}
public function get_username() {
return $this->_username;
}
public function get_password() {
return $this->_password;
}
public function get_password2() {
return $this->_password2;
}
}
registration class:
<?php
class registration {
function checkEmptyField(&$userdetails){
if ($userdetails-> get_fullname == ''){
return true;
}
elseif ($userdetails->get_email == ''){
return true;
}
elseif ($userdetails->get_contact == ''){
return true;
}
elseif ($userdetails->get_username == ''){
return true;
}
elseif ($userdetails->get_password == ''){
return true;
}
elseif ($userdetails->get_password2 == ''){
return true;
}
}
}
You ask for a property, not a method here: $userdetails-> get_fullname
Correct way: $userdetails-> get_fullname()
You should always turn on the error reporting, because this should have been reported by php.
The way you call registration::checkEmptyField() requires it to be declared as static.
<?php
class registration {
static function checkEmptyField(userdetails $userdetails) {
...
}
}
There is no need to prepend $userdetails with &, in PHP the objects are always passed by reference. It's better to use type hinting: prepend the parameter name ($userdetails) with its expected type (class userdetails in this case).
Related
I need to dynamically display user name from logged in user in my OOP PHP project. I can display it when I type right id from the database but it shows error when I try to define property $user_id in my function find_by_id. I need help on how to define $user_id variable. Here is my code:
index.php
<?php $user = User::find_by_id($user_id); ?>
<h1>Hello, <?php echo $user->username; ?></h1>
user.php
<?php
class User
{
protected static $db_table = "users";
public $id;
public $username;
public $password;
public $first_name;
public $last_name;
private function has_the_attribute($the_attribute)
{
$object_properties = get_object_vars($this);
return array_key_exists($the_attribute, $object_properties);
}
public static function instantation($the_record)
{
$the_object = new self;
foreach ($the_record as $the_attribute => $value) {
if ($the_object->has_the_attribute($the_attribute)) {
$the_object->$the_attribute = $value;
}
}
return $the_object;
}
public static function find_this_query($sql)
{
global $database;
$result_set = $database->query($sql);
$the_object_array = [];
while ($row = mysqli_fetch_array($result_set)) {
$the_object_array[] = self::instantation($row);
}
return $the_object_array;
}
public static function find_all()
{
return self::find_this_query("SELECT * FROM " . static::$db_table . " ");
}
public static function find_by_id($user_id)
{
global $database;
$the_result_array = self::find_this_query("SELECT * FROM " . self::$db_table . " WHERE id = $user_id");
return !empty($the_result_array) ? array_shift($the_result_array) : false;
}
public static function verify_user($username, $password)
{
global $database;
$username = $database->escape_string($username);
$password = $database->escape_string($password);
$sql = "SELECT * FROM " . self::$db_table . " WHERE ";
$sql .= "username = '{$username}' ";
$sql .= "AND password = '{$password}'";
$the_result_array = self::find_this_query($sql);
return !empty($the_result_array) ? array_shift($the_result_array) : false;
}
}
$user = new User();
session.php
<?php
class Session
{
private $signed_in = false;
public $user_id;
public $message;
public function __construct()
{
session_start();
$this->check_the_login();
$this->check_message();
}
public function login($user)
{
if ($user) {
$this->user_id = $_SESSION['user_id'] = $user->id;
$this->signed_in = true;
}
}
public function logout()
{
unset($_SESSION['user_id']);
unset($this->user_id);
$this->signed_in = false;
}
private function check_the_login()
{
if (isset($_SESSION['user_id'])) {
$this->user_id = $_SESSION['user_id'];
$this->signed_in = true;
} else {
unset($this->user_id);
$this->signed_in = false;
}
}
public function is_signed_in()
{
return $this->signed_in;
}
public function message($msg="")
{
if (!empty($msg)) {
$_SESSION['message'] = $msg;
} else {
return $this->message;
}
}
public function check_message()
{
if (isset($_SESSION['message'])) {
$this->message = $_SESSION['message'];
unset($_SESSION['message']);
} else {
$this->message = "";
}
}
}
$session = new Session();
For the sake of marking this as accepted, what you need to do is actually pass the user ID of the and not just an uninitialised variable, if your instance you are storing it in the session so I presume it would be:
<?php $user = User::find_by_id($_SESSION['user_id']); ?>
Note: To make your templating cleaner, you can use the shorthand syntax for echo:
<h1>Hello, <?= $user->username; ?></h1>
Another thing to note is that you have built a Session class, however you are still for some reason accessing the data through $_SESSION which doesn't make sense, make some setters / getters for it. Finally, sessions are something that you'll be using a lot therefore it would be worth making that class static.
Reading Material
echo
I am relatively new to PHP and am building the log-in portion of my website. I have attempted to get the code to work for to no avail and have become extremely frusturated. When I submit a valid username & password I get the error above
Fatal Error: Call to undefined method stdClass::_setSession() on line 58
I have tested the query separately from the rest of the code and fed the variables as they would be fed from the form (i.e. $User= "..." & $Pass="...") and the auth passes. Also, data not present in the database does not find a user (verified by the php logs).
I have done extensive searches on this error and I can't seem to make any of the answers I've found fit this instance (See additional info below for a few of the things I've tried that made sense to me). I have included the relevant file below. Thank you in advance for any help you provide!
Additional Info:
I have tried to remove the "new stdClass" definition for $This which creates the following error: "Warning: Creating default object from empty value" referring to the first $This encountered.
I have tried to change the stdClass definition to "User" and receive the following error: "Fatal error: Maximum function nesting level of '100' reached, aborting!" referring to the "new User" line.
Relevant File:
class User {
public $Id;
public $Email;
public $FirstName;
public $LastName;
public $Address;
public $City;
public $State;
public $Zip;
public $Phone;
public $PhoneType;
public $IsLoggedIn = false;
function __construct() {
if (session_id() == "" || !isset($_SESSION)) {
session_start();
}
$_SESSION['IsLoggedIn'] = false;
if (!isset($This)) {$This = new stdClass();}
$This->IsLoggedIn = false;
if (isset($_SESSION['IsLoggedIn']) && $_SESSION['IsLoggedIn']== true) {
$This->_initUser();
}
} //end __construct
public function authenticate($User,$Pass) {
$mysqli = new mysqli(DBHOST,DBUSER,DBPASS,DB);
if ($mysqli->connect_errno){
error_log("Cannot connect to MySQL: " .$mysqli->connect_error);
return false;
}
$hasher= new PasswordHash(8, false);
$SafeUser = $mysqli->real_escape_string($User);
$SafeUser = strtolower($SafeUser);
$IncomingPassword = $mysqli->real_escape_string($Pass);
$Stored_hash= "*";
$Query = "SELECT * FROM donors";
$QueryUser = $mysqli->query($Query);
while ($FindUserRow = $QueryUser->fetch_array()){
if ($FindUserRow['Email']== $SafeUser){
$Stored_hash = $FindUserRow['Password'];
if ($hasher->CheckPassword($IncomingPassword, $Stored_hash)) {
$Check = 'Authentication succeeded';}
else { error_log("Passwords for {$User} don't match");
$Check = 'Authentication failed';
return false;}
if (!isset($This)) {$This = new stdClass();}
$This->Id = $FindUserRow['Id'];
$This->Email = $FindUserRow['Email'];
$This->FirstName = $FindUserRow['First_Name'];
$This->LastName = $FindUserRow['Last_Name'];
$This->Address = $FindUserRow['Street'];
$This->City = $FindUserRow['City'];
$This->Zip = $FindUserRow['Zip'];
$This->State = $FindUserRow['State'];
$This->Phone = $FindUserRow['Phone'];
$This->PhoneType = $FindUserRow['Phone_Type'];
$This->IsLoggedIn = true;
$This->_setSession();
return true;}
else{
error_log("Cannot retrieve account for {$User}");
return false;}}
} //end function authenticate
private function _setSession() {
if (session_id() == '' || !isset($_SESSION)) {
session_start();
}
$_SESSION['Id'] = $This->Id;
$_SESSION['Email'] = $This->Email;
$_SESSION['FirstName'] = $This->FirstName;
$_SESSION['LastName'] = $This->LastName;
$_SESSION['Address'] = $This->Address;
$_SESSION['City'] = $This->City;
$_SESSION['Zip'] = $This->Zip;
$_SESSION['State'] = $This->State;
$_SESSION['Phone'] = $This->Phone;
$_SESSION['PhoneType'] = $This->PhoneType;
$_SESSION['IsLoggedIn'] = $This->IsLoggedIn;
} //end function setSession
private function _initUser() {
if (session_id() == '' || !isset($_SESSION)) {
session_start();
}
$This->Id = $_SESSION['Id'];
$This->Email = $_SESSION['Email'];
$This->FirstName = $_SESSION['FirstName'];
$This->LastName = $_SESSION['LastName'];
$This->Address = $_SESSION['Address'];
$This->City = $_SESSION['City'];
$This->Zip = $_SESSION['Zip'];
$This->State = $_SESSION['State'];
$This->Phone = $_SESSION['Phone'];
$This->PhoneType = $_SESSION['PhoneType'];
$This->IsLoggedIn = $_SESSION['IsLoggedIn'];
} //end function initUser
You have made it extra complicated. bad syntax if (!isset($This)) {$This = new stdClass();} this one is wrong practice. $this with lowercase t is something i.e. default object of the current class.
You are trying to overwrite object of User ($this) with stdClass, so parser is taking _setSession() a member method of stdClass instead of User and hence it is undefined by obvious. Try removing the bad syntax and use $this->_setSession() and replace $This to $this for better understanding.
I just can't figure it out.. but i got a feeling the problem is around there when im throwing the exception messages. I got almost the same code in my registration class. There is just give the errors array the messages normaly like $this->errors[] = "some error".
<?php
class class_login
{
private $id;
private $username;
private $password;
private $passmd5;
private $errors;
private $access;
private $login;
private $ltoken;
public function __cunstruct()
{
$this->errors = array();
$this->login = isset($_POST['login'])? 1:0;
$this->access = 0;
$this->ltoken = $_POST['ltoken'];
$this->id = 0;
$this->username = ($this->login)? $this->filter($_POST['lusername']) : $_SESSION['username'];
$this->password = ($this->login)? $this->filter($_POST['lpassword']) : '';
$this->passmd5 = ($this->login)? md5($this->password) : $_SESSION['password'];
}
public function isLoggedIn()
{
($this->login)? $this->verifyPost() : $this->verifySession();
return $this->access;
}
public function filter($var)
{
return preg_replace('/[^a-zA-Z0-9]/','',$var);
}
public function verifyPost()
{
try
{
if(!$this->tokenValid())
throw new Exception('Invalid Form Submission!');
if(!$this->isDataValid())
throw new Exception('Ivalid Form Data!');
if(!$this->verifyDatabase())
throw new Exception('Invalid Username/Password!');
$this->access = 1;
$this->registerSession();
}
catch(Exception $e)
{
$this->errors[] = $e->getMessage();
}
}
public function verifySession()
{
if($this->sessionExist() && $this->verifyDatabase())
$this->access = 1;
}
public function verifyDatabase()
{
include('db_connect.php');
$data = mysql_query("SELECT ID FROM users WHERE username = '($this->username)' AND password = '($this->passmd5)'");
if (mysql_num_rows($data))
{
list($this->id) = #array_values(mysql_fetch_assoc($data));
return true;
}
else
return false;
}
public function isDataValid()
{
return (preg_match('/[^a-zA-Z0-9](5,12)$/', $this->username) && preg_match('/[^a-zA-Z0-9](5,12)$/', $this->password))? 1:0;
}
public function tokenValid()
{
return (!isset($_SESSION['ltoken']) || $this->ltoken != $_SESSION['ltoken'])? 0 : 1;
}
public function registerSession()
{
$_SESSION['ID'] = $this->id;
$_SESSION['username'] = $this->username;
$_SESSION['password'] = $this->passmd5;
}
public function sessionExist()
{
return (isset($_SESSION['username']) && isset($_SESSION['password']))? 1 : 0;
}
public function show_errors()
{
foreach($this->errors as $key=>$value)
echo $value."</br>";
}
}
?>
The constructor is called __construct, not __cunstruct.
I see you are setting $this->errors to an array in your __cunstruct function, but since it is not __construct it may never be set.
You need a associative array for
foreach($this->errors as $key=>$value)
But you have no one. ($this->errors[] = $e->getMessage();)
With out an associative array you must use:
foreach($this->errors as $value)
public function __cunstruct() <------ The error is probably here. It is __construct
{
$this->errors = array();
$this->login = isset($_POST['login'])? 1:0;
$this->access = 0;
$this->ltoken = $_POST['ltoken'];
$this->id = 0;
$this->username = ($this->login)? $this->filter($_POST['lusername']) : $_SESSION['username'];
$this->password = ($this->login)? $this->filter($_POST['lpassword']) : '';
$this->passmd5 = ($this->login)? md5($this->password) : $_SESSION['password'];
}
You have a typo.... _construct and not _construct
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.
The question is simple:
How can i pass data from model to view(or back to the controller) to display errors like "your password is too short"
Here is the controller
class UsersController extends Controller {
private $username;
private $password;
function register()
{
if($_POST)
{
$this->User->username = $_POST['username'];
$this->User->password = $_POST['password'];
$this->User->register();
}
}
}
the model
class User extends Model {
public $username;
public $password;
function register()
{
$username = $this->username;
$password = $this->password;
if (!empty($username) && !empty($password))
{
// registration process
}
else
{
// "you must provide a username and password" or something like that
}
}
Just have your register function in your model return "PASSWORD"; to the controller and have your controller take the return from the model and return it to the view. Let the view interpret what the error output for "PASSWORD" is.
Example:
the controller
class UsersController extends Controller {
private $username;
private $password;
function register()
{
if($_POST)
{
$this->User->username = $_POST['username'];
$this->User->password = $_POST['password'];
return $this->User->register();
}
}
}
the model
class User extends Model {
public $username;
public $password;
function register()
{
$username = $this->username;
$password = $this->password;
if (!empty($username) && !empty($password))
{
// ...
return "SUCCESS";
}
else
{
return "PASSWORD";
}
}
}
the view
$responses = array("SUCCESS" => "Registered Successfully!", "PASSWORD" => "You must provide a username and password!");
$result = $this->UsersController->register();
echo $responses[$result];
Simply have your model methods to return a value, or throw exceptions, like any normal method. Then handle it in the controller. The view shouldn't touch the data directly from the model, that's the controller's job.
public function addAction()
{
$form = $this->_getForm();
$this->view->form = $form;
$this->render('add', null, true);
}
public function editAction()
{
$id = $this->getRequest()->getParam(0);
$Model = DI::get('yourclass_Model');
$form = $this->_getForm();
$data = $Model->getData();
$form->populate($data);
$this->view->flashMessages = $this->_helper->FlashMessenger->getMessages();
$this->view->form = $form;
$this->render('add', null, true);
}
public function saveAction()
{
$form = $this->_getForm();
$Model = DI::get('yourclass_Model');
try{
$saved = $Model->saveForm($form, $_POST);
} catch (Exception $e) {
echo "<pre>";
print_r($e);
exit;
}
if($saved)
{
$this->_helper->FlashMessenger('Record Saved!');
$this->_redirect("edit".$form->id->getValue(), array('exit'=>true));
}
$this->view->errorMessage = 'There were some errors';
$this->view->form = $form;
$this->render('add', null, true);
}
Create a class which implements Singleton pattern and ArrayAccess interface.
Or create something similar with dependency injection.
The ultimate solution would be if you create some validation architecture. (The model validates its self and it's error state is available in the views.)