I have a framework and I think I'm following something like the MVC pattern: A framework (the model) an index page that controls the input (the controller) and the views pages (that are included inside main.php/the main html)
I read a lot about structure and logics, to write a good application. I read many comments like "Why are you outputting anything if all you are going to do is try and redirect the user to another page?". Well the answer is, the most common case: redirect after the user successfully logged in. Do I need to print something? Of course, the whole main page with a login form/post. How I'm supposed to do that redirection??
So I'm a bit confused about logics and structure of the application. How do you store all the output and do the header redirection without printing anything?
I was thinking about using javascript to do the redirection but I also read comments saying; "if you write good code (following a good logic/structre), you won't need to use hacks like javascript redirection". How is that even possible?
Because the php output_buffering should not be enabled.
I have the output_buffering enabled, and I can use header (after output) without any problem. If I use the javascript redirection the whole page reloads, but using header it just loads the content (the views content that are included in main.php).
So how do you do this without output_buffering?
If you want to redirect to a success page AND pass messages - say, after a successful login - an easy solution is to use "flash" sessions, where you store a message in a SESSION and then, as soon as it's used, you discard it. You don't need to sore anything in the output buffer for this.
This is a very basic example, but should give you the gist of it.
login.php
if($login_successful) {
// put your message in the session
$_SESSION['message'] = 'Login Successful';
// redirect to the success page
header('location: success.php');
}
success.php
<?php
session_start();
// check if $_SESSION['message'] exists
if(isset($_SESSION['message'])) {
// print the message
echo $_SESSION['message'];
// clear the session
$_SESSION['message'] = null;
}
Looks like you are mixing up some things here. What you are talking about are actually two different requests. Either the user wants to view the main page, or he wants to log in using that form on your main page. In your index.php you would have something like this (pseudocode):
if (isLoginRequest) {
// user wants to log in
if( validateLogin($loginFormData) ) {
redirect('successful');
} else {
displayLoginError();
}
} else {
// user wants to view main page
echo main.html
}
Update to answer the question in the comments: The better alternative would be to leave your form validation stuff in login.php and refer to that in your login form <form action="login.php" .... Then in your login.php you would have something like this:
if (loginSuccessful) {
redirect('success.php');
// no need to call die() or whatever
} else {
setFlashMessage('Login failed'); // set a flash message like timgavin described
redirect('index.php')
// also no die() or whatever
}
index.php then is responsible to display your main page and, if set, rendering the flash message from a failed login attempt.
Simple solution: Move the login post script from login.php to another file (login_post.php). The same for other scripts using header() after dom output. (no need to change the form action="")
In index.php:
$url = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
//some more security checks like esc_url() (non-php function)
if ($url == '/login') {
include('header_pages/login_post.php');
}
// all these includes before including main.php
// where views pages are included and the DOM output starts
Since header() is inside the post script, no more headers already sent errors (And output_buffering off, of course).
Same for logout page that is currently being included inside main.php
Thanks to the other answers, they helped me finding this solution.
Related
im trying to finish my site and ensuring that the user cannot see anything that might help them in malicious ways or give them a bad experience on the site.
So for my pages where e.g login.php i check the request method, if its post continue if not then 404 etc.
However i have a couple of pages that gather some information from the database and i include them in the page. Some of them are quite large / complex so i prefer doing this to keep things tidier.
How can i go about redirecting the user to a 404 if they directly access these pages instead of them just being included?
Thanks. Hope you know what i mean! :)
<?php // top file, eg login.php
define('IN_SCRIPT', true);
include('infopage.php');
?>
<?php // included file, eg infopage.php
if (! defined('IN_SCRIPT')) {
// log message, throw header, etc.
// this is a direct access
exit(0);
}
// do whatever
?>
Alternatively, consider moving your info pages out of the web visible space.
I think that you can use some simple tricks.
where you want to include files, instead of simply
include('db.php')
do:
$including = 'yes';
include('db.php');
and in first lines of db.php:
if (!isset($including)) {
//show 404
exit;
}
//db job
so it does it's job if included, and shows a 404 if it is called directly.
Alternatively:
the first trick (and DEFINE) may be safer but if you don't want to change every file that includes the file;
just in db.php:
if (basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME'])) {
//show 404
exit;
}
//db job
i'm new to php, and i'm having a hard time establishing proper session mgmt. controls to prevent unauthorized access to a specific section of my site. I'll give an example...
myimaginarysite.com/application/index.php has a form to auth the user and it will redirect you to 'portal.php' after successful auth. 'portal.php' will check for a valid session as part of an include and then based on that it will either send u back to authenticate via header("location....) or just load up the HTML content. Now, if an unauthorized user hits 'portal.php' directly.. because they won't have a valid session.. they will get redirected back to the index, however, if you proxy the traffic you will see that the whole HTML content for 'portal.php' will actually be sent to the client (although not displayed on the browser) before redirecting back to the login page. So my question is... am I missing something, is there a way to make sure the HTML content is suppressed and is not sent to the client??
below is a snippet of my code for 'portal.php'
<?php
include "includes/checksession.php";
?>
<html>
<body>
Who Am I ??
<br></br>
Log Off
.....bunch of authenticated content.....
</body>
</html>
You need to stop script execution after sending the redirect headers with die() or exit(). Header redirection only sets the http headers, otherwise the page content is the same unless you instruct it otherwise.
Stopping script execution, like Juhana suggested, is probably the easiest solution for now, but there are other possibilities of course. You can just make the output conditional:
<?php
if (checkSession())
{
// redirect to login page
}
else
{
// output HTML.
}
If your site grows larger, it will probably (hopefully) also be more structured. If so, it might be easier to include other page fragments. So your code could look like this at first:
if (!checkSession())
{
include 'loginpage.php';
}
else
{
include 'portalpage.php';
}
And eventually maybe:
if (!checkSession())
{
ApplicationContext.setController(new LoginPageController());
}
Whatever the case, exit works fine and may be useful, especially for a case like this, but it terminates your script quite abrubtly, so it might get in the way of other processes that you may want to include, like debug-output or logging, profiling, and stuff like that.
Hey so I have create a login system to a website and I wish to have this login appear when I type in my address. When I have typed in details and logged in, I wish to be redirected to another PHP file, but with the same address.... this way, All I need to do is type in my address if I am allready logged in and I will go to the site which requires login.
I have made a transaction happen identifing if the session is created, if it is, it redirects me to another page, but also to another URL. I tried googleing it, but couldn't find anything exact and straight forward.
Currently:
Login page:
www.example.com
Member page:
www.example.com/members
What I wish for:
Login page:
www.example.com
Member page:
www.example.com
The program structure should look like this.
index.php
if (user is logged in)
display dashoard
else
display login page
Since you are using PHP, make use of session functions. Thus, URL rewriting is no longer necessary.
Update
Assuming if you have file structure in PHP like this:
- index.php
- login.php
+ template
- login.php
- dashboard.php
You can do the following structure in index.php file.
define('IN_FILE', true);
if (isset($_SESSION['user'])) {
require 'template/dashboard.php';
} else {
require 'template/login.php';
}
In template/dashboard.php
if (!defined('IN_FILE')) {
exit;
}
// Then your HTML, PHP and whatnot
And in login.php
if (!isset($_SESSION['user'])) {
require 'template/login.php';
} else {
header('Location: index.php');
}
Change the code according to your needs.
This can be achieved using several approaches.
a) Use session to determine the current page, so if a user click on a link, create a session store the value and on page load read the session data and include the file accordingly.
b) Use URL parameter to determine the page (this is the most common approach). for example in index.php you can add more parameters like index.php?page=somepage and by reading the value using $_GET and including the PHP file accordingly.
There are some more way to achieve what you want to, for instance using javascript/jQuery this is possible.
I have the following PHP script within a file named login.php
<?php
$ref = $_SERVER['HTTP_REFERER'];
if ($ref == 'http://example.com/dir/invalid.php' || $ref == 'http://www.example.com /dir/invalid.php') {
echo '
<div id="invalid">
TESTTESTTESTTESTTESTTESTTESTTEST
</div>
';
}
?>
I have deliberately went to the invalid.php page (which redirects using header() to login.php) and this div does not show up. Does it have something to do with the referrer not really being invalid.php or is there an issue with the script?
Thanks
I don't think the HTTP_REFERER is what you think it is. Namely, it is the page from which the user followed a link to the current page. However, it's very unreliable as we rely on the browser of the user to correctly report this value.
I would suggest the option I thought you needed, except that the only one I can think of you might doesn't really makes sense... (checking if the url matches a url that's not the current script)... so I do not see what you are trying to do.
As promised several ways to do what you want to achieve:
First off, I don't like this solution at all and really consider it ugly, but it's the one closest to what you where trying to do.
invalid.php
require 'login.php'; // we include the file instead of referring to it
login.php
if ($_SERVER['SCRIPT_NAME'] == 'invalid.php')
{
// do whatever
}
The main difference between what you did and what I did for the user will be that here the url bar will show that you're at invalid.php and not somewhere else. This also means that refreshing doesn't make the message go away.
A better solution in my opinion is the following:
In your script that logs a user in (checks the database and everything):
if (!valid_login()) // pseudo-code, obviously
{
$_SESSION['invalid_login'] = true;
header('Location: login.php');
// previously, we had something like this instead of the two lines above:
// header('Location: invalid.php');
}
in login.php
if (isset($_SESSION['invalid_login']) && $_SESSION['invalid_login'])
{
$_SESSION['invalid_login'] = false;
// do whatever
}
Of course, this should be done with proper session facilities like starting up the session in both those files. Instead of using session variables, you could include the file and use normal variables or send GET variables through the header request, but both those solutions share a problem: refreshing doesn't make the message disappear. However, if you were to move the code from the top file of the two above to login.php (if it's not already there, I don't know what file that actually is...) you could once again use normal variables instead of session variables and have a solution in which refreshing does make it go away. In this case, you might argue that you are cluttering your files with bussiness logic and presentation, but there are solutions to that (like keeping it in a separate file, and including it into login.php, moving the html to another file and including that one into login.php or both.
I have an HTML page that I do not want to be available unless the login is successful. My login starts a session, however I don't know how to check for the session in the HTML and if the session exists I want to display the page, if not I want to display a unauthorised message. How can I do this?
You can't check for the session in the HTML per se you'd have to do it in PHP. Depending on how your page is built using PHP you could try putting something like this at the top of your HTML file:
<?php
if (!isset($_SESSION['my_login_var'])) {
echo 'Unauthorised';
exit();
}
?>
But you'd be far better off doing this earlier on in your PHP code, in which case you could use the header function to send the user to a proper 403 page.
UPDATE
Usually PHP does some processing before the HTML is outputted and the headers are sent to the connecting client, so you want to send a 403 header before that output happens. This could be in an included PHP file that is run before the HTML is built, or even in the HTML file itself if no other content has been outputted before the script reaches that point.
You can make a small adjustment to the code above to send a 403 header and 'properly' deny access to the page:
<?php
if (!isset($_SESSION['my_login_var'])) {
header('HTTP/1.1 403 Forbidden');
exit();
}
?>
You're going to need to look up PHP sessions. See http://us.php.net/manual/en/function.session-start.php for PHP session_start() documentation.
Basically you will need to do session_start(). If the login is successful, set a session variable like $_SESSION['logged_in'] = true;. Then do some logic on your page and redirect/display message depending on the result.
You should attempt something and come back and ask a more specific question if you have problems.