I am using the Active Record in Code Igniter and I have the following code in my controller for my profile:
$data = array(
'first_name' => $_POST['first_name'],
'last_name' => $_POST['last_name'],
'email_address' => $_POST['email_address'],
'gravatar_email' => $_POST['gravatar_email']
);
$this->db->where('user_id', $session_data['id']);
$this->db->update('user_profiles', $data);
redirect('profile', 'refresh');
How do I do the redirect only if the update was successful or not? Also I would like to display a message to my user.
First of all, you shouldn't be accessing $_POST directly, there are helpers for that ($this->input->post('name') since they sanitize the data when used properly).
Secondly, you use something like $this->db->affected_rows(); to determine how many rows were changed and then judge what happened.
In your update, you might update 1 element, or x, you need to test for that before doing a redirect.
Hope that helps, when all else fails, read the CI guide, it is very well written.
Reference:
Query Helpers
Input Class / POST / GET etc;
Related
I am using CakePHP for my application, where I have a User model. This User has a password, which has a regex to validate.
The regex forces the user to use a password at least 6 characters long, containing at least 1 number and special char.
The validation looks like this:
'password' => array(
'ruleName' => array(
'rule' => array('custom', '/^.*(?=.{6,})(?=.*\d)(?=.*[a-zA-Z])(?=.*[##$%^&+=]).*$/i'),
'message' => 'Password not legit',
'allowEmpty' => true
)
)
When I want to edit my password, this validation works great. But when I want to edit the user (no option to change password there), the $this->User->save() fails.
If I debug my $this->User->validationErrors, the only thing shown is:
array(
'password' => '*****'
)
The password field is not set in my post data, so the validation should not happen at all.
When I comment this block of validation code, the user can be saved.
Anyone knows what I am doing wrong?
I solved it myself already. Before saving the User object, I already did a $this->User->Read(null, $userid) for other purposes.
This resulted in remembering the values of the read (including password) in the $this->User object.
Since the save method is called on the $this->User object, the password value is trying to get saved too. But since *** isn't valid according to the regex, the save fails.
Thanks for the help anyway!
I was investigating CakePHP (2.3.4) Model::save method to insert new records and ran into a little snag:
//Two fields provided, email field intended to fail validation
$data = array('Member' => array(
'username' => 'hello',
'email' => 'world'
));
$this->Member->create();
var_dump($this->Member->save($data, true));
The above save() will return false and no data will be written to the database. However if I change the data to:
//One field provided, intended to pass validation
$data = array('Member' => array(
'username' => 'hello'
));
then save() will attempt to write a new record to database with a blank email field. I realize that skipping validation for unspecified fields might be a useful behavior during updates, but is there a CakePHP recommended way to handle partially empty data sets when creating new records? Thanks a lot.
Edit:
Thanks to Sam Delaney for the tip. In case anybody else gets stumped, this did the trick: CakePHP Data Validation: field 'required' key
This key accepts either a boolean, or create or update. Setting this key to true will make the field always required. While setting it to create or update will make the field required only for update or create operations. If ‘required’ is evaluated to true, the field must be present in the data array. For example, if the validation rule has been defined as follows:
I had originally baked the model and forgotten that required => true was left out of the validation rule. Setting it to true or 'create' would've avoided me blank records getting inserted due to gibberish data array.
IMHO what you've experienced is the desired behavior. Consider that you have the same two fields within a form and the user provides a value for only username. Both username and email field are submitted even though email is empty. Then on the server, you try to save the record only to find out that it has failed validation which you feedback to the user. On the other hand, perhaps in your system it is perfectly possible to create a user without requiring an email (for example root access account), CakePHP's validation implementation allows both of these scenarios.
If this flexibility isn't what you desire, just set the required attribute for your validation rule as true:
public $validate = array(
'email' => array(
'rule' => 'email',
'required' => true
)
);
This will satisfy your all or nothing requirement.
Hi friends I am just wondering what security should i keep in mind when users on my site post anything using form. I have encrypted codeigniter session and also enabled the feature to store session in database, and my example Model function is like this in below. I have enabled form validation and enabled xss and csrf globally.
I think sql injection is automatically handled by CI's active record function. Please suggest me what else do i have to check before taking this site in production. Thanks
function AddSomeMemberPost(){
$now = date('Y-m-d H:i:s', strtotime('now'));
$data = array(
'topic' => $this->input->post('title'),
'status' => 'draft',
'content' => $this->input->post('body'),
'category_id' => $this->input->post('categoryid'),
'featured' => '0',
'lang' => $this->input->post('lang'),
'pubdate' => $now,
'video' => $this->input->post('tube_video'),
'user_id' => $this->session->userdata('user_id'),
'username' => $this->session->userdata('username')
);
$this->db->insert('my_table', $data);
validation are done this way, Do i need to validate session data btw ? It is going thru model.
$this->form_validation->set_rules('topic', 'Topic', 'required|min_length[8]|max_length[90]');
$this->form_validation->set_rules('content', 'Content', 'required|min_length[8]');
$this->form_validation->set_rules('tags', 'Tag', 'required|miax_length[50]');
$this->form_validation->set_rules('video', 'Youtube Video Link', 'min_length[8]');
It is recommended that you change the PHP error reporting level, which is set in the main /index.php file.
error_reporting(0)
NOTE: You can set this in a hook instead, so you can leave the standard CI files unchanged.
In general, you should clean ALL data before putting it into any SQL (including data used in a session), even when using the built-in CI DB functions. For example, you should always cast numbers before adding them to SQL
$val = (int)$val;
(NOTE: For performance you can check if these values are even in a valid range before attempting to run a query, to save yourself from running queries you know will return nothing. For example, if you're searching for a value that is a positive integer, then you don't need to run a query if $val <= 0)
I FINALLY got my hasMany data to save using saveAll() - (an Event that hasMany Schedules).
I got it to work by repeating through the $this->data['Schedule'] data on the events/admin_edit.ctp, and building out all the fields for any/all schedules that are related to that event.
This seems fine (I think), but my question/problem is - I had to add the Schedule.id and Schedule.event_id fields as hidden fields so it'd know what data to save. This seems awfully unsecure/wrong... 1) is it the right way to do it? and 2) Couldn't someone just edit the field to another ID, and hit save to update a different event's information?
My next assumption is that I'll have to build in some kind of checks into the controller before doing the saveAll()... but the more I write, the more complicated it's going to get, and the less Cake-like it seems.
Any thoughts/suggestions on how to better do what I'm doing, or insight as to what to check before doing the saveAll() is greatly appreciated.
I assume you have users that are allowed to edit their own events. If that's the case, the easiest way is to add a validation rule that verifies that the user is allowed to edit the submitted schedule.
In your action, before the save() is called, inject the current user id into each record. ie:
$this->data['Schedule'][0]['user_id'] = $this->Auth->user('id');
This may not work exactly, but should get you close. In your Schedule model, add a validation rule:
var $validate = array(
'user_id' => array(
'rule' => 'checkAuth'
'message' => 'Nice try buddy.',
'on' => 'update'
)
);
function checkAuth() {
$authorized = true;
if(!$this->hasAny(array(
'Schedule.id'=>$this->data['Schedule']['id'],
'Schedule.user_id' => $this->data['Schedule']['user_id']))) {
$authorized = false;
}
return $authorized;
}
I'm new to CakePHP and I'm stuck in reading a Model using other fields. I did a cake bake command to generate a simple users CRUD. I can view the user using the url CakePHP provided.
/users/view/1
I can view the user using id = 1. What if I want to view a user by name instead of id?
/users/view/username
By default the view function reads the User model by id.
$this->User->read(null, $id)
Thank you.
you can use find function or findBy<Field>() in your case findByUsername()
check this
I've never used cakePHP myself but I'm going to suggest that you will likely have to implement a new user model method, something like getUserByUsername($username)
This would then in turn interface with your DAL that would get the details of that user based on the username and return a user object that can be used however you wish...
It seems that CakePHP is focusing to deprecate some functions, such as findAll(). Perhaps soon the magic methods such as findBy<field>() will have the same fate.
I can recommend what martswite is suggesting, you should create your custom function:
function findUser($username=''){
return $this->find('first', array(
'conditions' => array(
'User.username' => $username
)
));
}
Perhaps you have a status field, maybe the profile isn't public, you can add a condition:
function findUser($username=''){
return $this->find('first', array(
'conditions' => array(
'User.username' => $username,
'User.status' => 1
)
));
}
I think that's more modular than findBy<Field>.