Guys i have error in my php mvc code when am updating my profile it tell me error while updating l check my well but it seem am suck and don't know what to do. please help me!
it keep on warning me with this warning
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in C:\xampp\htdocs\php.dev\classes\Model.php on line 37
This my classes/Model.php file
abstract class Model {
protected $dbh;
protected $stmt;
public function __construct() {
$this->dbh = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASS);
}
public function query($query) {
$this->stmt = $this->dbh->prepare($query);
}
// binds the prepare statement
public function bind($param, $value, $type = null) {
if (is_null($type)) {
switch (true) {
case is_int($value):
$type = PDO::PARAM_INT;
break;
case is_bool($value):
$type = PDO::PARAM_BOOL;
break;
case is_null($value):
$type = PDO::PARAM_NULL;
break;
default:
$type = PDO::PARAM_STR;
}
}
$this->stmt->bindValue($param, $value, $type);
}
public function execute() {
$this->stmt->execute();
}
public function resultSet() {
$this->execute();
return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function lastInsertId() {
return $this->dbh->lastInsertId();
}
public function single(){
$this->execute();
return $this->stmt->fetch(PDO::FETCH_ASSOC);
}
public function emailExist() {
$this->execute();
return $this->stmt->fetch(PDO::FETCH_ASSOC);
}
}
and here's my controllers/user.php
class Users extends Controller{
protected function profile(){
if (!isset($_SESSION['is_logged_in'])) {//if user do not login they can not profile page
header('Location: '.ROOT_URL.'shares');
}
$viewmodel = new UserModel();
$this->returnView($viewmodel->profile(), true);
}
}
and here's my models/user.php code
public function profile(){
// Sanitize POST
//$post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
if(isset($_POST['updateProfile'])){
$name = $_POST['name'];
$email = $_POST['email'];
if (empty($_POST['name']) || empty($_POST['email'])) {
Messages::setMsg('Please Fill All Form Fields', 'error');
return;
}
// check if email is already taken
$this->query('SELECT * FROM users WHERE email = :email');
$this->bind(':email', $_POST['email']);
$row = $this->emailExist();
if ($row) {
Messages::setMsg('Email already Exist', 'error');
return;
} else {
# Update the MySQL
$this->query("UPDATE users SET name =:name, email =:email WHERE id =:id");
$this->bind(':name', $_POST['name']);
$this->bind(':email', $_POST['email']);
$this->execute();
// Verify
if($this->lastInsertId()){
Messages::setMsg('Successfull Updated', 'success');
return;
} else {
Messages::setMsg('Error while updating data', 'error');
return;
}
}
}
return;
}
and here's my views/users/profile.php code
<form method="post" action="<?php $_SERVER['PHP_SELF']; ?>">
<div class="form-group">
<label>Name</label>
<input type="text" name="name" class="form-control" value="<?php echo $_SESSION['user_data']['name'];?>" />
</div>
<div class="form-group">
<label>Email</label>
<input type="text" name="email" class="form-control" value="<?php echo $_SESSION['user_data']['email'];?>" />
<!-- input type="hidden" name="id" class="form-control" value="<!?php echo $_SESSION['user_data']['id']?>" / -->
</div>
<input class="btn btn-primary" name="updateProfile" type="submit" value="Submit" />
</form>
If the user doesn't already exist, it runs:
$this->query("UPDATE users SET name =:name, email =:email WHERE id =:id");
Which is attempting to update an existing user, instead of adding a new one. The query fails with an error because you haven't bound anything to :id (and you shouldn't, because you're attempting to add a new user).
Instead try this query:
INSERT INTO users SET name =:name, email =:email
and it should work. It still won't allow you to edit users, but it will allow you to add new ones.
Related
It doesn't update the data it keeps giving me an error. If the email already exist, it should tell me email exist but it can not update user data.
It give me this error:
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: no parameters were bound in C:\xampp\htdocs\php.dev\classes\Model.php on line 37
classed/Model.php
abstract class Model {
protected $dbh;
protected $stmt;
public function __construct() {
$this->dbh = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASS);
}
public function query($query) {
$this->stmt = $this->dbh->prepare($query);
}
// binds the prepare statement
public function bind($param, $value, $type = null) {
if (is_null($type)) {
switch (true) {
case is_int($value):
$type = PDO::PARAM_INT;
break;
case is_bool($value):
$type = PDO::PARAM_BOOL;
break;
case is_null($value):
$type = PDO::PARAM_NULL;
break;
default:
$type = PDO::PARAM_STR;
}
}
$this->stmt->bindValue($param, $value, $type);
}
public function execute() {
$this->stmt->execute();
}
public function resultSet() {
$this->execute();
return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function lastInsertId() {
return $this->dbh->lastInsertId();
}
public function single(){
$this->execute();
return $this->stmt->fetch(PDO::FETCH_ASSOC);
}
public function emailExist() {
$this->execute();
return $this->stmt->fetch(PDO::FETCH_ASSOC);
}
}
controllers/users.php
class Users extends Controller{
protected function profile(){
if (!isset($_SESSION['is_logged_in'])) {//if user do not login they can not profile page
header('Location: '.ROOT_URL.'shares');
}
$viewmodel = new UserModel();
$this->returnView($viewmodel->profile(), true);
}
protected function register(){
if (isset($_SESSION['is_logged_in'])) {//if user do not logout they can not access register page
header('Location: '.ROOT_URL.'shares');
}
$viewmodel = new UserModel();
$this->returnView($viewmodel->register(), true);
}
protected function login(){
if (isset($_SESSION['is_logged_in'])) {//if user do not logout they can not access login page
header('Location: '.ROOT_URL.'shares');
}
$viewmodel = new UserModel();
$this->returnView($viewmodel->login(), true);
}
protected function logout(){
unset($_SESSION['is_logged_in']);
unset($_SESSION['user_data']);
session_destroy();
// Redirect
header('Location: '.ROOT_URL);
}
}
models/user.php
class UserModel extends Model {
public function profile() {
// Sanitize POST
$post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
if($post['updateProfile']) {
#$name = $post['name'];
#$email = $post['email'];
#$id = $post['id'];
if (empty($post['name']) || empty($post['email'])) {
Messages::setMsg('Please Fill All Form Fields', 'error');
return;
}
// check if email is already taken
$this->query('SELECT * FROM users WHERE email = :email');
$this->bind(':email', $post['email']);
$row = $this->emailExist();
if ($row) {
Messages::setMsg('Email already Exist', 'error');
return;
} else {
# Update the MySQL
$this->query("UPDATE users SET name =:name, email =:email WHERE id =:id");
$this->execute();
// Verify
if($this->lastInsertId()){
Messages::setMsg('Successfull Updated', 'success');
return;
} else {
Messages::setMsg('Error while updating data', 'error');
return;
}
}
}
return;
}
}
view/users/profile.php
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Update Data</h3>
</div>
<div class="panel-body">
<form method="post" action="<?php $_SERVER['PHP_SELF']; ?>">
<div class="form-group">
<label>Name</label>
<input type="text" name="name" class="form-control" value="<?php echo $_SESSION['user_data']['name'];?>" />
</div>
<div class="form-group">
<label>Email</label>
<input type="text" name="email" class="form-control" value="<?php echo $_SESSION['user_data']['email'];?>" />
<input type="hidden" name="id" class="form-control" value="" />
</div>
<input class="btn btn-primary" name="updateProfile" type="submit" value="Submit" />
</form>
</div>
</div>
Your class function execute() needs to accept array values for the bound parameters in your sql string.
In classed/Model.php change:
public function execute() {
$this->stmt->execute();
}
To:
public function execute($params=NULL) {
$this->stmt->execute($params);
}
You are not binding variables to the specified variable names in your sql string.
models/user.php - Replace:
$this->execute();
With:
$this->execute(array(':name' => $post['name'], ':email' => $post['email'], ':id'=>$post['id']));
I have a Class to manage the users and everything was working fine until I had to add more columns to the table and modify 2 names. Now one of the modified names, the function that returns the column content is not working, the colum is fill with data but it's not printing anything when I call the function.
I rechecked many times the code, looking for a bad typed name or something, but everything seems to be fine, I can't find the problem...
This is my class:
require_once('aet.php');
class staff {
private $aet;
private $not_working_column;
private $working_column;
public function __construct() {
$this->aet = new aet();
}
private function generate($staff) {
$this->not_working_column = $staff->not_working_column;
$this->working_column = $staff->working_column;
}
private function addInformation($stmt) {
$i = 0;
$stmt->bind_result($not_working_column, $working_column);
while ($stmt->fetch()) {
$arrayStaff[$i] = new staff();
$arrayStaff[$i]->setNotWorkingColum($not_working_column);
$arrayStaff[$i]->setWorkingColumn($working_column);
$i++;
}
}
public function StaffFromEmail($email) {
$mysqli = $this->aet->getAetSql();
if ($stmt = $mysqli->prepare("SELECT * FROM staff WHERE email = ? LIMIT 1")) {
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 0) {
$exit = false;
}
else {
$arrayStaff = $this->addInformation($stmt);
$this->generate($arrayStaff[0]);
$exit = true;
}
}
return $exit;
}
public function setNotWorkingColum($not_working_column) {
$this->not_working_column = $not_working_column;
}
public function getNotWorkingColum() {
return $this->not_working_column;
}
public function setWorkingColumn($working_column) {
$this->working_column = $working_column;
}
public function getWorkingColumn() {
return $this->working_column;
}
}
And in the form where users can update their info
<div class="item">
<div class="input">
<input type="text" placeholder="" name="staff_info[]" value="<?php echo $staff->getNotWorkingColum(); ?>" />
</div>
</div>
<div class="item">
<div class="input">
<input type="text" placeholder="" name="staff_info[]" value="<?php echo $staff->getWorkingColumn(); ?>" />
</div>
</div>
I've also made a video https://www.youtube.com/watch?v=9S_Uw7IK_xY
My fault, while changing the name of a column I missed one:
public function setPersonalPhone($personal_phone) {
$this->phone = $personal_phone;
}
Should be:
public function setPersonalPhone($personal_phone) {
$this->personal_phone = $personal_phone;
}
I'm still following the login/register tutorial I have went over the videos a few times to see if maybe I made a typing mistake somewhere but I can't seem to find anything the error I'm getting is "Notice: Trying to get property of non-object"
I did look around it was suggested to try the below solution however it didn't work:
echo $user[0]->data()->username;
I know it has something to do with my data class, well I think it's my data class that's wrong.
index.php
<?php
require_once 'core/init.php';
if(Session::exists('home')){
echo '<p>' . Session::flash('home', 'You have been registered and can now log in!') . '</p>';
}
$user = new User();
echo $user->data()->username;
?>
Login
User.php
<?php
class User{
private $_db,
$_data,
$_sessionName;
public function __construct($user = null){
$this ->_db = DB::getInstance();
$this->_sessionName = Config::get('session/session_name');
if(!$user){
if(Session::exists($this->_sessionName)){
$user = Session::get($this->_sessionName);
if($this->find($user)){
$this->_isLoggedIn = true;
}else{
//logout
}
}
} else{
$this->find($user);
}
}
public function create($fields = array()){
if($this->_db->insert('users', $fields)){
throw new Exception('There was a problem creating account');
}
}
public function find($user = null){
if($user){
$field = (is_numeric($user)) ? 'id' : 'username';
$data = $this->_db->get('users', array($field, '=', $user));
if($data->count()) {
$this->_data = $data->first();
return true;
}
}
return false;
}
public function login($username = null, $password = null){
$user = $this->find($username);
if($user){
if($this->data()->password ===Hash::make($password, $this->data()->salt)){
Session::put($this->_sessionName, $this->data()->id);
return true;
}
}
return false;
}
public function data(){
return $this->_data;
}
}
Login.php
<?php
require_once 'core/init.php';
if(Input::exists()){
if(Token::check(Input::get('token'))){
$validate = new Validate();
$validation = $validate->check($_POST, array(
'username' => array('required' => true),
'password' => array('required' => true)
));
if ($validation->passed()){
//log user in
$user = new User();
$login = $user->login(Input::get('username'), Input::get('password'));
if($login){
echo 'Success';
}else{
echo'<p>Sorry invalid details</p>';
}
} else{
foreach($validation->errors() as $error)
echo $error, '<br />';
}
}
}
?>
<form action="" method="POST">
<div class="field">
<label for="username" id="username"> Username </label>
<input type="text" name="username" id="username" autocomplete="off">
</div>
<div class="field">
<label for="password" id="password"> Password </label>
<input type="password" name="password" id="password" autocomplete="off">
</div>
<input type="hidden" name="token" value="<?php echo Token::generate();?>">
<input type="submit" value="Login">
</form>
Home
Session.php
<?php
class Session {
public static function put($name, $value){
return #$_SESSION[$name] = $value;
}
public static function get($name)
{
return self::exists($name) ? #$_SESSION[$name] : null;
}
public static function exists($name)
{
return #$_SESSION[$name] !== null;
}
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);
}
}
}
I'm assuming this is the offending code:
$user = new User();
echo $user->data()->username;
This code instantiates a User object, and we can see that the constructor expects the username (or possibly id?) to be given. If no username is given it looks like the find function simply returns false and hence the data array will be empty. This is why you get the error message.
Try calling the constructor with the current username, e.g.
$user = new User('test');
If it's possible for the index page to be loaded without a username, then you just need to add an additional check on the data object before you try to use it, e.g.
if (#$user->data())
echo $user->data()->username;
else
echo "Not logged in";
Basic typing mistake in my init.php file, I really hate myself...
I have been attempting to make a login system with php oop however I have come across this error Warning: Illegal offset type....classes\Session.php on line 11 I'm not quite sure where I'm going wrong any advice would be appreciated.
login
if(Input::exists()){
if(Token::check(Input::get('token'))){
$validate = new Validate();
$validation = $validate->check($_POST, array(
'username' => array('required' => true),
'password' => array('required' => true)
));
if ($validation->passed()){
//log user in
$user = new User();
$login = $user->login(Input::get('username'), Input::get('password'));
if($login){
echo 'Success';
}else{
echo'<p>Sorry invalid details</p>';
}
} else{
foreach($validation->errors() as $error)
echo $error, '<br />';
}
}
}
?>
<form action="" method="POST">
<div class="field">
<label for="username" id="username"> Username </label>
<input type="text" name="username" id="username" autocomplete="off">
</div>
<div class="field">
<label for="password" id="password"> Password </label>
<input type="password" name="password" id="password" autocomplete="off">
</div>
<input type="hidden" name="token" value="<?php echo Token::generate();?>">
<input type="submit" value="Login">
</form>
User
<?php
class User{
private $_db,
$_data,
$_sessionName;
public function __construct($user = null){
$this ->_db = DB::getInstance();
$this->_sessionName = Config::get('session/session_name');
}
public function create($fields = array()){
if($this->_db->insert('users', $fields)){
throw new Exception('There was a problem creating account');
}
}
public function find($user = null){
if($user){
$field = (is_numeric($user)) ? 'id' : 'username';
$data = $this->_db->get('users', array($field, '=', $user));
if($data->count()) {
$this->_data = $data->first();
return true;
}
}
return false;
}
public function login($username = null, $password = null){
$user = $this->find($username);
if($user){
if($this->data()->password ===Hash::make($password, $this->data()->salt)){
Session::put($this->_sessionName, $this-data()->id);
return true;
}
}
return false;
}
private function data(){
return $this->_data;
}
}
Session
<?php
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);
}
}
}
index
<?php
require_once 'core/init.php';
if(Session::exists('home')){
echo '<p>' . Session::flash('home', 'You have been registered and can now log in!') . '</p>';
}
echo Session::get(Config::get('session/session_name'));
?>
You should check if session key exist before trying to access it:
<?php
class Session {
public static function put($name, $value){
return $_SESSION[$name] = $value;
}
public static function get($name)
{
return self::exists($name) ? $_SESSION[$name] : null;
}
public static function exists($name)
{
return #$_SESSION[$name] !== null;
}
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);
}
}
}
I like the idea of using FUSE models for validation in RedbeanPHP.
My applications sometimes require accepting data through multiple sources (form, file, etc.), so putting the validation on the actual class update makes sense.
Looking at the examples on the Redbean site, the validation seems to be based on throwing an exception.
Of course, you can only throw one exception, so I am assuming I'd need to create an additional property of type "array" in my FUSE class to hold validations messages associated with individual fields.
Does anyone have any better ideas? Here's what I've been trying thus far...
<form action="" method="post">
<p>your name: <input name="name" type="text"></p>
<p>your email: <input name="email" type="text"></p>
<p>your message:</p>
<textarea name="message" id="" cols="30" rows="10"></textarea>
<input name="send" value="send message" type="submit">
</form>
<?php
/**
* #property $name string
* #property $email string
* #property $message string
*/
class Model_Comment extends RedBean_SimpleModel{
public $invalid = array();
public function update(){
if(empty($this->name)) $this->invalid['name'] = "field is empty";
if(empty($this->email)) $this->invalid['email'] = "field is empty";
if(empty($this->message)) $this->invalid['message'] = "field is empty";
if(count($this->invalid) > 0) throw new Exception('Validation Failed!');
}
public function getInvalid(){
return $this->invalid;
}
}
if(isset($_POST['send'])){
$comment = R::dispense('comment');
/* #var $comment Model_Comment */
$comment->import($_POST,'name,email,message');
try{
R::store($comment);
}
catch(Exception $e){
echo $e->getMessage();
$invalid = $comment->getInvalid();
print_r($invalid);
exit;
}
echo '<p>thank you for leaving a message.</p>';
}
echo "<h2>What people said!</h2>";
$comments = R::find('comment');
/* #var $comments Model_Comment[] */
foreach($comments as $comment){
echo "<p>{$comment->name}: {$comment->message}</p>";
}
?>
You can extend RedBean_SimpleModel class to add your own methods and fields to it, so it will work with all your model. Then, you can use transactions to manage your validations. It could look like this (code not tested):
class RedBean_MyCustomModel extends RedBean_SimpleModel {
private $errors = array();
public function error($field, $text) {
$this->errors[$field] = $text;
}
public function getErrors() {
return $this->errors;
}
public function update() {
$this->errors = array(); // reset the errors array
R::begin(); // begin transaction before the update
}
public function after_update() {
if (count($this->errors) > 0) {
R::rollback();
throw new Exception('Validation failed');
}
}
}
Then, your model could look like this:
class Model_Comment extends RedBean_MyCustomModel {
public function update(){
parent::update();
if(empty($this->name)) $this->error('name', 'field is empty');
if(empty($this->email)) $this->error('name', 'field is empty');
if(empty($this->message)) $this->error('name', 'field is empty');
}
public function getInvalid(){
return $this->invalid;
}
}