I am new to CI and would normally try to pass some information back to a login page like the following...
public function authenticate()
{
$this->load->model('User_model', '', true);
if ($this->User_model->authenticate($this->input->post('username'), $this->input->post('password')))
{
$this->session->set_userdata('loggedin', true);
header('Location: /');
}
else
{
header('Location: /sessions/login/error?='.'1');
}
}
And then on the login page use a _GET.
So how would I best go about this in CodeIgniter?
First of all, using GET for sensitive data like email/password is a general no-no. Bad practice all the way.
But the answer to your question is here - http://www.codeigniter.com/userguide3/libraries/input.html
$this->input->get('username') is equal to $_GET['username'].
You might use $this->input->get('username', TRUE) to escape some malicious code.
And $this->input->post('username') is equal to $_POST['username']. This is what I advise you to use (it requires modification of your HTML though)
From my understanding you want to pass _GET variables for the error codes, right? as i see you are using _POST variables for the form as you should.
As you are working with Codeigniter, you can use the URI structure of the framework and instead of working with _GET work with the MVC structure.
So, instead of redirecting this:
header('Location: /sessions/login/error?='.'1');
Redirect like this:
header('Location: /sessions/login/error/1');
Then in your controller for the login, in the error method:
function error($msgId = 0) {
// here you will get the number you sent in the url as $msgId
}
If you still need to work with _GET variables, that is possible as well. go to the main application config file of the framework /aplication/config/config.php and have a look on the Enable Query Strings section
Related
I am working on a basic HTML/PHP form for user registration. It works fine but have a problem I would like to solve. I've noticed that during testing that when I press submit and the passwords don't match, I'm taking to the error page (by design), then redirected back to registration where I have to enter everything all over again. Is there a way to keep the fields populated with the user's input so that they can just go back and correct what needs to be fixed instead of having to re-enter everything all over again?
Best way would be to use AJAX so they never have to leave the page in the first place.
Failing that, using history.back() to send the user back should keep the form info there.
Failing that, save their form data in a $_SESSION variable and use that to repopulate the form.
You can save submitted data in session:
-Init a php session by <?php session_start(); ?>, this function must appear BEFORE the tag
-store a variable in session like this: $_SESSION['myVar']=$myVar;
-retrieve it back (in another page) by : $myVarFromSession = $_SESSION['myVar'];
-Finally, destroy the session and its content : <?php session_destroy(); ?>
Quick — Dirty
Send back the username/password in a query string (?username=...&password=...)
Set SESSION variables before redirecting
Better — Encapsulate Logic into Classes
I strongly recommend encapsulating your various moving parts in classes that handle the request, form, validation, error message, and rendering/routing logic. You will find this infinitely easier than trying to manually throw error messages/data back and forth between scripts. If your site/app is big, or if you want to follow best practices and become a better developer, classes are the way to go.
Take a look at how different frameworks handle this problem. Some good ones are Yii, Laravel, and Symfony2. Right out of the box they'd be able to quickly and easily solve this problem.
Sample Code
class LoginForm
{
public $password;
public $username;
public function validate()
{
// Perform validation
}
}
class HttpRequest
{
public function getIsPostRequest()
{
return 'POST' === $_SERVER['REQUEST_METHOD'];
}
public function getPost($name, $default=null)
{
return isset($_POST[$name]) ? $_POST[$name] : $default;
}
}
// This code processes the request to your login page.
// View::renderFile() renders a "view", which is a mix
// of HTML/PHP code that gets served back to the browser.
$request = new HttpRequest();
$form = new LoginForm();
if ($request->getIsPostRequest()) {
$form->username = $request->getPost('username');
$form->password = $request->getPost('password');
if ($form->validate()) {
// Login the user...
}
}
View::renderFile('login.php', array(
'form' =>$form,
));
Storing the user's password in the session or passing it in the query parameters is a security no-no. You should display the error on the same form page to avoid redirecting and losing that data. That way the error is still displayed and the script still has the user's input data from the $_POST. Of course, Dan Schmidt's recommendation to use a framework is excellent. The purpose of the framework is to save you from the headache you're experiencing right now.
If you insist on redirecting to an error page, then you can store the username in the session, but I highly recommend against storing the password as mentioned before.
I have a login form on my website that checks submitted usernames/passwords. If there's no match, the user is sent back to the login page and an appropriate error message is displayed. The call for this redirect is this:
header("location:../login.php?error_message=$error_message");
This works fine, but it does look messy in the browser's address bar (especially with descriptive error messages). Is there any way to do this automatic redirect without using the $_GET variable? I had considered using the $_SESSION variable, but that doesn't seem like the best coding practice.
Thanks for reading.
What about having a simpler GET variable?
// something.php
header ("Location: foo.php?err=1");
And then in the page handling the errors:
// foo.php
$errors = array (
1 => "Hello, world!",
2 => "My house is on fire!"
);
$error_id = isset($_GET['err']) ? (int)$_GET['err'] : 0;
if ($error_id != 0 && in_array($error_id, $errors)) {
echo $errors[$error_id];
}
Hope this helps.
If you don't wish to use sessions, you could use error codes instead:
header('Location: ../login.php?error=' . urlencode($error_code));
Then, inside login.php:
if (isset($_GET['error'])) {
switch ($_GET['error']) {
case 123: // ...
break;
}
}
Instead of a bulky switch, you could use a lookup array for error messages instead (can be language dependent).
Btw, using relative URIs in your header redirects is not recommended, an absolute (e.g. /login.php) or fully qualified URI (e.g. http://example.org/login.php) is preferred.
For the form validation you have 3 options:
Use AJAX to validate - so, there will be no need to redirect at all.
Use redirect and session to store the error message along with entered data.
Use redirect as a part of the POST/Redirect/GET patterm
Personally I would implement (1) and (3) for my forms. (1) for the convenience of ordinary user and (3) for backward compatibility with paranoids like myself.
Using sessions is indeed a cleanest way for the redirec-based validations, as it will leave no POSTed page in the history under any circumstances. However, in a presence of AJAX-based validation it seems a bit overkill
You can use session based flash messages.
Look at this example : http://mikeeverhart.net/php/session-based-flash-messages/
Using session is a good option. You can clear session value as soon as you display error. But if you don't want to use session you can modified your url like following.
// login failed
header("location:../login.php?status=0");
I prefer to use session.
I use a code to connect gmail and get my friends list. In that code there is a function call
redirect('https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token='. $oauth->rfc3986_decode($accrss_token['oauth_token']), 'location');
I've searched for function redirect() but didn't find it in the php manual. Is it a built in function in php?
The 2nd parameter is 'location' what is the use of that parameter?
Here is the function where it's used:
public function connect_google($oauth=null){
if(!$oauth)
{
return null;
}
//create a gmailcontacts objects
$getcontact = new GmailGetContacts();
$accrss_token = $getcontact->get_request_token($oauth, false, true, true);
$this->ci->session->set_userdata('oauth_token', $accrss_token['oauth_token']);
$this->ci->session->set_userdata('oauth_token_secret', $accrss_token['oauth_token_secret']);
//redirect to google auth
redirect('https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token='. $oauth->rfc3986_decode($accrss_token['oauth_token']), 'location');
}
It is part of the CodeIgniter URL helper. See:
http://codeigniter.com/user_guide/helpers/url_helper.html
From the documentation:
Does a "header redirect" to the URI specified. If you specify the full site URL that link will be build, but for local links simply providing the URI segments to the controller you want to direct to will create the link. The function will build the URL based on your config file values.
As you've said, it isnt a built in function, so we dont know what it should look like.
However, considering the name i guess it should look like this:
function redirect($url, $header)
{
header("$header: $url");
}
Since sending a Location: {ur} header will redirect your page to another.
Use header: http://php.net/manual/en/function.header.php
header('Location: urlOfDestination');
It is probably a user defined function. It probably works hand in hand with header() hence the name, the first parameter is the page to redirect to, and the second one is to tell the function that it is indeed a redirect to the location. Just check out the header function.
I.e. would you recommend me to use one controller method like this:
function save()
{
if(!is_bool($this->input->post('')))
{
$post_data = $this->input->post('');
$this->mymodel->save($post_data);
}
$this->load->view('myview');
}
Or would you recommend writing it using two methods?
function save()
{
if(!is_bool($this->input->post('')))
{
$post_data = $this->input->post('');
$this->mymodel->save($post_data);
}
redirect('controller/method2')
}
The redirect is the crucial difference here. It prohibits resubmissions from update for example.
How do you do it? Is there another better way?
You should always redirect on a successful form post.
You should always redirect on a successful form post.
Absolutely. For anyone wondering why this is the case, here are a couple of the reasons:
Avoid "duplicate submissions". Ever had that when you innocently click refresh or hit the back button and wham, everything has resubmitted?
Being friendly to bookmarks. If your user bookmarks the page, presumably you want them to return where they created it, rather than a blank form (a redirect makes them bookmark the confirmation/landing page.
Further reading:
http://en.wikipedia.org/wiki/Post/Redirect/Get
As Aren B said, redirection is a good idea, but what I would change in your code is that validation of the post data should be done with the form validation functionallity. It is not only more reauseable but the code will get shorter.
If you want to handle AJAX requests, you would need to return something else than a via or a redirection.
I have a few pages that require login, so all controllers that link to these pages start with
$this->checkSession();
//...rest of the code
CheckSession should verify the session is still live, otherwise display a message and stop the execution of the rest of the code in the controller:
function checkSession()
{
if (!$this->session->userdata('is_logged_in'))
{
//the session has expired!
$data['main'] = 'confirmation_message';
$data['title'] = "Session expired";
$this->load->vars($data);
$this->load->view('template');
exit();
}
}
.
I was expecting these instructions to happen in sequence, but I only get a blank page.
How can I make sure exit() gets executed only after all views are loaded?
In this case Pedro is correct. If they are not logged in just redirect them, it's even better if you can use Public/Admin named base controllers to stop you having to do this in each separate protected file.
Generally speaking though, if you use exit() it will stop the Output library for running. If you just want to stop the current controller from executing but allow output of the controller you can use return in exactly the same way.
function checkSession()
{
return (bool) $this->session->userdata('is_logged_in');
}
Then simply:
if(!$this->checkSession())
{
//the session has expired!
$data['main'] = 'confirmation_message';
$data['title'] = "Session expired";
$this->load->vars($data);
$this->load->view('template');
return;
}
exit() should only ever be used if you really want instant death of your application's execution for debugging, error reporting, etc.
In this case you should not use exit, what you should do if the session is not valid is redirect your app using example:
redirect('/init/login/','refresh');
I had a similar problem. Where I wanted to stop the user to due to no login. But I wanted to offer a list of links for them not simply redirect them to a login page. I am using CI version 1.7.2 and the $this->_output() $this->display->_output() and $this->output->_display() solutions did not work for me. I was however to get my results using the $this->output->get_output() function.
$this->load->vars($data);
$this->load->view('template');
die($this->output->get_output());
$this->output->_display();
exit();
Is the correct answer! Thanks to Sam Sehnert... It's hidden in the comments so thought I'd re-post.
I don't know enough about codeigniter's workflow but it seems to me that you want to redirect to the login page instead of trying to render it. Evidently, none of the code you supplied sends the template to the browser by the time exit() is called.
exit() cuts your scrip there and the actual _output() function of the controller is never called. What you need to do is add action in one of your controllers for example the user login screen and redirect there. You can use the flashdata function from the Session - http://codeigniter.com/user_guide/libraries/sessions.html to pass your message and then catch it inside your view and display it.
Another way which is not very smart but should work is to forcefully call the output function.
function checkSession()
{
if (!$this->session->userdata('is_logged_in'))
{
//the session has expired!
$data['main'] = 'confirmation_message';
$data['title'] = "Session expired";
$this->load->vars($data);
$this->load->view('template');
$this->_output();
exit();
}
}
Actually in the newest CI function to manually call output class is
$this->display->_output();
and don't be worried - it handles caching, content will also be properly gzipped if you set so in config
I usually add and extended controller with login logic that handles login functions, so that if a normal controller is one that is needing an auth then the login method is called automatically and the original content is not displayed. It's a good solution if you would like to stay on the page the user tried to access without redirecting (and then posting him back to the same page)
Put the code in a variable and write it.
$html = $this->load->view('template',null,true);
echo $html;
exit();