I Learning a framework Kohana.
What is difference between Kohana::message and Kohana::config?
They perform the same function.
Maybe if there is a difference between the concept?
Kohana:message
These are generally used to store messages that will be displayed to the user. For example if you have a method that tries to create a user and it fails, you can get the relevant you can you may have the following in a User Controller:
$create = $this->create_user($user);
if($create)
{
// user created
$message = Kohana::message('user', 'create_success');
}
else
{
// failed to create user
$message = Kohana::message('user', 'create_error');
}
Kohana:config
This is used for configuration information such as the hash_method used in auth module and you can access it using Kohana::$config->load('auth.hash_method')
One is for configuration information. The other is for reusable text: Kohana::message('registration.error.email') could say something like "There is already an account using the email address you entered, an email with instruction on how to reset you password has been sent in case you forgot it.".
Related
The agiletoolkit Auth/basic class allow to try to login without any limitation.
And i'm searching a way to limit the number of failed login attempt, i've tried to override some methods of this class but it use ajax reloading so php code is not executed correctly.
Any suggestion is welcome.
Many Thanks,
Inspired by StackOverflow I have implemented the following protection:
for each user we store soft / hard lock. Hard lock would refuse to verify password even if it's correct.
soft lock is a period of time after which we will reset "unsuccessful attempt" counter.
every time you type incorrect password both soft and hard lock increase making you wait longer (but not forever)
gradual increase puts a reasonable limit so if your attacker tries to hack your account for a hour - he will only get several attempts in, yet your account will be OK to log-in after few hours.
I have implemented this in one of my projects, although it's not a controller, but a built-in code. Please look through comments and I hope this will help you and others:
In User model add:
$this->addField('pwd_locked_until');
$this->addField('pwd_failure_count');
$this->addField('pwd_soft_unlock');
You'll also need two methods:
/* Must be called when user unsuccessfully tried to log-in */
function passwordIncorrect(){
$su=strtotime($this['pwd_soft_unlock']);
if($su && $su>time()){
// aw, they repeatedly typed password in, lets teach them power of two!
$this['pwd_failure_count']=$this['pwd_failure_count']+1;
if($this['pwd_failure_count']>3){
$this['pwd_locked_until']=date('Y-m-d H:i:s',time()
+pow(2,min($this['pwd_failure_count'],20)));
$this['pwd_soft_unlock']=date('Y-m-d H:i:s',time()
+max(2*pow(2,min($this['pwd_failure_count'],20)),60*5));
}
}else{
$this['pwd_failure_count']=1;
$this['pwd_soft_unlock']=date('Y-m-d H:i:s',time() +60*5);
}
$this->save();
}
and
/* Must be called when user logs in successfully */
function loginSuccessful(){
$this['last_seen']=date('Y-m-d H:i:s');
$this['pwd_soft_unlock']=null;
$this->save();
}
Finally - you can use this as a login form:
class Form_Login extends Form {
function init(){
parent::init();
$form=$this;
$form->setModel('User',array('email','password'));
$form->addSubmit('Login');
if($form->isSubmitted()){
$auth=$this->api->auth;
$l=$form->get('email');
$p=$form->get('password');
// check to see if user with such email exist
$u=$this->add('Model_User');
$u->tryLoadBy('email',$form->get('email'));
// user may have also typed his username
if(!$u->loaded()){
$u->tryLoadBy('user_name',$form->get('email'));
}
// incorrect email - but say that password is wrong
if(!$u->loaded())$form->getElement('password')
->displayFieldError('Incorrect Login');
// if login is locked, don't verify password at all
$su=strtotime($u['pwd_locked_until']);
if($su>time()){
$form->getElement('password')
->displayFieldError('Account is locked for '.
$this->add('Controller_Fancy')
->fancy_datetime($u['pwd_locked_until']));
}
// check account
if($auth->verifyCredentials($u['email'],$p)){
// resets incorrect login statistics
$u->loginSuccessful();
$auth->login($l);
// redirect user
$form->js()->univ()->location($this->api->url('/'))->execute();
}else{
// incorrect password, register failed attempt
$u->passwordIncorrect();
$form->getElement('password')->displayFieldError('Incorrect Login');
}
}
}
}
This should be converted into add-on by someone.
I think you may store numbers of usage of Model_User (usually used in Auth) in session or cookies using afterLoad hook and then check it where you need to.
Oops. FAILED login. So you model is NOT loaded.
You need just to count clicks on a button of a login form and store it somewhere (cookies, database). So create your own login form and add some condition when a form is submitted like:
$m = $this->add('Model_User');
$f = $this->add("Form");
$f->setModel($m, array('email', 'password'));
$f->addSubmit("Log In");
if ($f->isSubmitted()){
//Limmiting
if($_COOKIE[$this->api->name."_count_failed_login"] >= 5/*Here's you limit number*/){
/*redirect or something else*/
}
if (/*here should be you condition*/){
$_COOKIE[$this->api->name."_count_failed_login"] = 0;
$this->api->auth->login($f->get("email"));
$f->js()->univ()->redirect("index")->execute();
}else{
/* when login is failed*/
if($_COOKIE[$this->api->name."_count_failed_login"]){
$_COOKIE[$this->api->name."_count_failed_login"]++;
}else{
$_COOKIE[$this->api->name."_count_failed_login"] = 1;
}
$this->js()->univ()->alert('Wrong username or password')->execute();
}
}
I didn't check it. Maybe some adjastements are needed.
Just an idea.
Hope that helps.
I am a total php beginner. I actually want to customize a survey platform for visual stimuli for my needs as I need this for my thesis. The original version of this survey platform asks participants for their mail address to login then they see the available tests. As far as I understand it the code checks if the mail address is already saved in the database and if not reserves a certain number of the stimuli for the respective participant (with the use of their mail address as identifier). This number of stimuli will then be blocked from further tests. This however poses to problems:
1) participants can just participate once
2) participants have to give up their anonymity
The whole thing doesn't have to be very sophisticated. It would be sufficient if participants could log in with the word "anonymous" and then come to available tests where a certain number of stimuli is reserved not by their mail address but i.e. by an automatically produced unique random number which serves as an identifier.
I think the important lines of code are the following:
/**
* Lets user login. Stores new e-mail addresses if not yet in database.
*/
function login() {
$this->validation->set_error_delimiters('<div class="error">', '</div>');
$this->validation->set_message('required', $this->lang->line("validation_error_validemail_required"));
$this->validation->set_message('valid_email', $this->lang->line("validation_error_validemail_required"));
// check if valid e-mail address
//required|valid_email
$rules['email'] = "required|valid_email";
$this->validation->set_rules($rules);
$fields['email'] = $this->lang->line("frontend_user_email");
$this->validation->set_fields($fields);
if ($this->validation->run() == FALSE) {
$this->load->view('welcome_message'); // reload form
} else {
$this->load->model("testcontainer_model", 'testcontainer');
$this->data['testcontainer']->activeuser = $this->data['testcontainer']->getUserByEmail($_POST['email']);
$this->load->view('welcome_message', $this->data);
}
}
/**
* Logout user, unset session data.
*/
function logout() {
$this->session->unset_userdata('user_email');
$this->session->unset_userdata('user_id');
$this->session->unset_userdata('albumpath_relative');
$this->session->unset_userdata('test_name');
$this->session->unset_userdata('test_id');
$this->load->view('welcome_message');
}
Would you please be so nice to help me modifying this code to get what I want want? I am grateful for every help!
Best regards,
Andreas
Forms in CI can be complex. This can be a very helpful tool if you wan to save some time too:
http://formigniter.org/app/index.php/formigniter/index/5
I want people to request invites to use my app, they fill in their email address, but how can generate an url for them to go to register? Presumably only to be used once! I was thinking some sort of md6 code using php!
P.S. If there is a tutorial for this, please give a the link. Thanks.
In the email you use a random code, for example (a part of) the session-id of the user
<?php
$code = session_id();
You save this code somewhere in your database and when the user hits your register page (for example, http://mydomain.tld/register?code=here-register-code), you do something like this:
<?php
$code = $_GET['code'];
if (my_code_is_valid($code) {
echo 'Hey, you are able to register now!';
} else {
echo 'Sorry friend, you need an invite first!';
}
You need to define your my_code_is_valid() function, but that's depending on your own code (framework, database system etc).
I'm using Drupal autoresponder module - and I want to use tokens so I can include the username who has subscribed within the emails being sent...
Does anybody know how this can be achieved?
Thanks for any help.
Shane
Thanks for that - your answer was very close....
The autoresponder module UID is not related to the user UID so your code was bringing in a different username... So I changed it to find the user from the email address instead.
// load the full user object
$user = user_load(array('mail' => $u->mail));
// Replace user tokens in mail body
$mail->body = token_replace($mail->body, 'user', $user);
Yes indeed, I'll submit it as a patch to my other request, and hopefully it may help somebody else.
Many Thanks
Shane
EDIT after separate answer by OP: The following was based on the assumption that the $u->uid refers to the 'standard' Drupal user id, which is not correct! So one has to find the corresponding Drupal user by other means, if possible - see the OPs answer for details on this...
I have not tested it, but looking at the autoresponder source code, you should be able to add (user) token replacement in the autoresponder_mail() function by inserting the following code before the preparation of the plain text body (before line 392 in the 6.x-1.0-alpha1 release):
// load the full user object
$user = user_load($u->uid);
// Replace user tokens in mail body
$mail->body = token_replace($mail->body, 'user', $user);
Alternatively, you could do it one function call earlier in autoresponder_cron(), within the while ($message db_fetch_object($result_messages)) loop, before the if (autoresponder_mail($u, $message)) call (line 366), using $message instead of $mail:
// load the full user object
$user = user_load($u->uid);
// Replace user tokens in mail body
$message->body = token_replace($message->body, 'user', $user);
In case this works, you might want to submit it as a patch to the already existing feature request for this. (I guess you are the 'keyzo'/'shane' who already answered there ;)
If it works and you are going to create a patch, it would be 'standard' practice to add the hint on possible token replacement to the message definition form(s) in autoresponder_mail_edit_create_form().
I have a problem with the following implementation of hook_cron in Drupal 6.1.3.
The script below runs exactly as expected: it sends a welcome letter to new members, and updates a hidden field in their profile to designate that the letter has been sent. There are no errors in the letter, all new members are accounted for, etc.
The problem is that the last line -- updating the profile -- doesn't seem to work when Drupal cron is invoked by the 'real' cron on the server.
When I run cron manually (such as via /admin/reports/status/run-cron) the profile fields get updated as expected.
Any suggestions as to what might be causing this?
(Note, since someone will suggest it: members join by means outside of Drupal, and are uploaded to Drupal nightly, so Drupal's built-in welcome letters won't work (I think).)
<?php
function foo_cron() {
// Find users who have not received the new member letter,
// and send them a welcome email
// Get users who have not recd a message, as per the profile value setting
$pending_count_sql = "SELECT COUNT(*) FROM {profile_values} v
WHERE (v.value = 0) AND (v.fid = 7)"; //fid 7 is the profile field for profile_intro_email_sent
if (db_result(db_query($pending_count_sql))) {
// Load the message template, since we
// know we have users to feed into it.
$email_template_file = "/home/foo/public_html/drupal/" .
drupal_get_path('module', 'foo') .
"/emails/foo-new-member-email-template.txt";
$email_template_data = file_get_contents($email_template_file);
fclose($email_template_fh);
//We'll just pull the uid, since we have to run user_load anyway
$query = "SELECT v.uid FROM {profile_values} v
WHERE (v.value = 0) AND (v.fid = 7)";
$result = db_query(($query));
// Loop through the uids, loading profiles so as to access string replacement variables
while ($item = db_fetch_object($result)) {
$new_member = user_load($item->uid);
$translation_key = array(
// ... code that generates the string replacement array ...
);
// Compose the email component of the message, and send to user
$email_text = t($email_template_data, $translation_key);
$language = user_preferred_language($new_member); // use member's language preference
$params['subject'] = 'New Member Benefits - Welcome to FOO!';
$params['content-type'] = 'text/plain; charset=UTF-8; format=flowed;';
$params['content'] = $email_text;
drupal_mail('foo', 'welcome_letter', $new_member->mail, $language, $params, 'webmaster#foo.org');
// Mark the user's profile to indicate that the message was sent
$change = array(
// Rebuild all of the profile fields in this category,
// since they'll be deleted otherwise
'profile_first_name' => $new_member->profile_first_name,
'profile_last_name' => $new_member->profile_last_name,
'profile_intro_email_sent' => 1);
profile_save_profile($change, $new_member, "Membership Data");
}
}
}
To safely switch users
http://api.drupal.org/api/function/session_save_session/6
<?php
global $user;
$original_user = $user;
session_save_session(FALSE); // D7: use drupal_save_session(FALSE);
$user = user_load(array('uid' => 1)); // D7: use user_load(1);
// Take your action here where you pretend to be the user with UID = 1 (typically the admin user on a site)
// If your code fails, it's not a problem because the session will not be saved
$user = $original_user;
session_save_session(TRUE); // // D7: use drupal_save_session(TRUE);
// From here on the $user is back to normal so it's OK for the session to be saved
?>
Taken from here:
drupal dot org/node/218104
yes i confirm drupal cron user profile is "anonymous" so you have to add the permission de manager user for the "anonymous" user which is not very good in term of security ..
Not quite a random guess ... but close ...
When "real" cron runs code, it runs it as a particular user.
Similarly, when you run the Drupal cron code manually, the code will also be running as a particular user.
My suspicion is that the two users are different, with different permissions, and that's causing the failure.
Does the cron job's user have access to write the database, or read only?
Are there any log files generated by the cron job?
Update: By 'user' above, I'm referring to the user accounts on the host server, not Drupal accounts. For example, on a sandbox system I use for testing Drupal changes, Apache runs under the noone account.
profile_save_profile dosn't check for permissions or as far as I can see do 'global $user' so I don't know if this is the real issue.
$new_member = user_load($item->uid);
This looks wrong user_load should take an array not a uid (unless you are using Drupal7), but if that didn't work the rest of the code would fail too.