Jump to content

Confused about non working header redirect


Recommended Posts

I've got an issue with a header redirect that is confusing me. I haven't been able to find any similar problems that have help me solve it and the PHP man page on headers isn't helping me either.

<?php
  if(isset($_POST['add_cat'])) {
      $cat_obj->add_category($_POST['cat_title']);
      header("Location: admin/category.php");
  }
?>

This code is in a file called add_category.php which is in the same directory as the category.php file I want it to redirect to.

without the 'header..' line it works perfectly; but with the 'header..' line I get the following warning -

Quote

Warning: Cannot modify header information - headers already sent by (output started at /opt/lampp/htdocs/**/**/admin/add_category.php:2) in /opt/lampp/htdocs/**/**/admin/add_category.php on line 30

 

but there's no other place sending headers (that I can see) and to my inexperienced eye it seems like it's cyclical logic as it's saying the same line I want to send the redirect is the one that already sent it. Would someone mind giving me an ELI5 breakdown of why this isn't working properly and maybe a route to solving the problem, please? TIA

Link to comment
Share on other sites

Anything that is in a php file, but outside the <?php .. ?> will be sent to the browser. Sending anything to the browser will cause (default) headers to be sent.

An empty line before the opening <?php will cause this.

An included php file that ends with

?>
\n

will send output. (For that reason never put ?> at end of included files).

Thus it doesn't have to be an explicit header() call in your code.

Also, when you call a header() like you have done, always "exit" after the call. If you don't the remainder of the page will still be executed.

Link to comment
Share on other sites

Barand, thank you for your reply.

I'm still a little lost on how to implement what you just taught me into this file. I'm sorry if I sound totally stupid.

here is the complete add_category.php file -

<?php require_once("../../load.php"); ?>

<?php require('includes/header.php'); ?>

  <section id="container" class="">

    <?php require('includes/top_nav.php'); ?>

    <?php require('includes/side_bar.php'); ?>
    
    <section id="main-content">
      <section class="wrapper">
        
        <div class="row">
          <div class="col-lg-12">
            <h3 class="page-header"><i class="fa fa-laptop"></i> Add Category</h3>
            <ol class="breadcrumb">
              <li><i class="fa fa-home"></i><a href="index.php">Home</a></li>
              <li><i class="fa fa-laptop"></i>Category</li>
              <li><i class="fa fa-plus"></i>Add Category</li>
            </ol>
          </div>
        </div>
        
        <?php
            if(isset($_POST['add_cat'])) {
                $cat_obj->add_category($_POST['cat_title']);
                header("Location: category.php");
            }
        ?>

        <div class="container row">
         
            <form action="" method="post" role="form" class="col-lg-6">
                <h3>Add Category</h3>
                <div class="form-group">
                    <input type="text" name="cat_title" placeholder="Category" class="form-control">
                </div>
                <div class="form-group">
                    <input type="submit" name="add_cat" placeholder="Add Category" class="btn btn-primary">
                </div>
            </form>

        </div> <!-- end row-->

      </section> <!-- end wrapper -->
    </section> <!-- end main content-->
  </section> <!-- end container -->
  
  <!-- footer includes scripts -->
  <?php require('includes/footer.php'); ?>

From what you're saying I'm getting this warning because of the HTML that appears before the php class call (if statement). I've tried putting that PHP code before the html and it doesn't redirect to category.php although I don't get the warning message either, but it does add the category to the db. Putting the html inside the php tags obviously just results in a lot of red flagged errors from my IDE, as would happen if I took out the ?> part of the tag

 

Is there a more correct way to redirect to category.php at the end of that if statement? Again, sorry if I'm sounding stupid but I don't understand how to properly implement what you've responded.

Link to comment
Share on other sites

Before you get to your header() you have already sent about 20 lines of HTML to the browser. Headers have to be sent before any other output.

You should rearrange your code so that php code comes at the top and html at the end, as far as possible. That way any redirects are done before any output is sent.

Edited by Barand
Link to comment
Share on other sites

Ok, I've tried many variations of that without succes.

I've been vaguely following a tutorial about this and in the instructors code he uses the header() function in the middle of HTML.

here's a SS of the paused video - image.png.32a57c6045fcf00f927a726bdab1bcdb.png

 

Why is this working for him and not for me?

Link to comment
Share on other sites

1 minute ago, TechnoDiver said:

Why is this working for him and not for me?

If it works for him then that's because he's using a non-standard PHP configuration which allows him to get away with bad practices such as processing form data and sending redirects in the middle of output.

Again: what he is doing is wrong. You should stop following that tutorial and instructor and find someone else to learn from.

Like Barand said, this type of code should happen at the start of your script and the output should happen at the end of your script. Mixing them together causes problems.

Link to comment
Share on other sites

21 minutes ago, TechnoDiver said:

Ok, I've tried many variations of that without succes.

the code on a page should be laid out in this general order (yes there are exceptions) -

  1. initialization
  2. post method from processing code (the current problem you are having with a redirect)
  3. get method business logic - code that knows how to get/produce the data/content needed for the dynamic portions of the page
  4. html document

 

  • Like 1
Link to comment
Share on other sites

Posted (edited)

OK, thank you all for your responses. All of them got me thinking in a different way. I do alright with Python but I find with PHP in web development it's much harder for me to visualize the flow of data because of the different forms and protocols all working together, it's a level of abstraction I'm still training my mind for.

Thanks again and I"ll work on cleaning up this code. The structure Mac_gyver gave will help for sure

 

I think what really has me a bit lost on this particular problem is, if the redirect has to go on top, how to connect that to an action later in the page? I'm not even sure what to search for about this particular issue, do any of you have any links to resources where I could learn about this exact thing?

Edited by TechnoDiver
afterthought
Link to comment
Share on other sites

Given what you've posted, there isn't an action later in the page. You're checking for a value in $_POST, which will be set on page load after clicking a fomr's submit button (assuming that form's action parameter is set to 'post'). So you can check if $_POST['cat_title'] is set at the top of your page and redirect if it is. You don't want to render half a page then redirect a user anyway, right?

Link to comment
Share on other sites

10 minutes ago, TechnoDiver said:

if the redirect has to go on top, how to connect that to an action later in the page?

the post method form processing code's purpose is to detect and process the data from a post method form submission. when you are done doing that and execute a redirect, there's no connection between any code that was just executed and what will be executed after the redirect.

perhaps this will help your understanding - web servers are stateless. they don't know or care about anything that happens outside of the current request they are servicing. a browser makes a http(s) request to a web server. the web server outputs the requested page, which can contain dynamic portions produced by server-side languages, e.g. php. the browser renders the html, css, and JavaScript on the page. if the page contains a html post method form (what you are currently doing), when that form is submitted, the form data is sent as part of the http(s) request to the page, given by the action attribute (a blank in your case, for the same page as the form. which is not actually valid html5. you should completely remove the form's action attribute in html5.) the section of the code on that page that's testing for a post method form submission will run, doing whatever it was written to do.

there are two reasons for putting the post method form processing code above the remainder of the php code on the page - 1) allow any statement that uses a header to work (redirect, cookie, content type, ...), and 2) so that you can make a decision as to what to do on rest of the page based on the result of the post method from processing code. if the result contained any user correctable errors, you would continue running the code on the page, display the errors, and re-display the html document with the html form in it. if the result was successful processing of the form data, you should actually redirect to the exact same url of the current page, with an exit/die statement after it, as @Barand stated, to cause a get request for that page. this will prevent the browser from trying to re-submit the form data should you reload the page or browse away from and back to the page.

each of these requests/responses are completely separate. it's up to the code you write on a page as to what happens during any request made to that page.

Link to comment
Share on other sites

OK, so I got this issue working but it is ugly, to say the least. I realized what was actually confusing me was how to get the header() function at the top of the page and still work with the require() statements I had up there (require_once('load.php') and require('header.php').

This is what I had in header.php -

require_once("../../load.php");
require('class/User.php');
require('class/Category.php');

$user = $user_obj->get_username(); 
$cat_obj = new Category($conn, $user);

but there's also HTML in header.php so I couldn't put the header() function before it nor after it in the add_category.php file (if I put it before then it didn't work because of the HTML getting sent before the header() function, and if I put it after than the necessary classes weren't instantiated in time.

So I removed all the above code from the header.php file and put it at the top of both the add_category.php file AND the category.php file that it redirects to.

It also seems completely wrong to me that the require_once('load.php') isn't in the header.php file and that all that code needs to be repeated in both pages rather than just in the header.php file.

Is this correct or is there a far more efficient way that this could have been done?

Link to comment
Share on other sites

1 hour ago, TechnoDiver said:

Is this correct or is there a far more efficient way that this could have been done?

There is almost certainly a better way, but I don't know what's in your include files so it's hard to say exactly what you'd need to do.

It sounds like you mostly just have a code ordering problem.  The solution is to re-arrange your code in a more functional way.  For example, there's no reason you should need to get rid of your header.php file and duplicate the code directly into the other pages.  If your header.php file is initializing variables that you need for your redirect code, then the proper solution is to move those initializations somewhere else, such as initializations.php.  Then you could order your code like:

require 'initializations.php';

if(isset($_POST['add_cat'])) {
    $cat_obj->add_category($_POST['cat_title']);
    header("Location: admin/category.php");
    exit;
}

require 'header.php';
//...

Also, note the exit; after the redirect.  You need that so the page will stop executing and not do anything unintended.

 

Link to comment
Share on other sites

require 'initializations.php';

if(isset($_POST['add_cat'])) {
    $cat_obj->add_category($_POST['cat_title']);
    header("Location: admin/category.php");
    exit;
}

To me there should be some kind of check to see if the add_category method/function to see if it actually did what it say. The way it's written now it blind faith that it worked and the reason for the header redirect?

 

This is what I'm talking about

require 'initializations.php';

if(isset($_POST['add_cat'])) {
    $result = $cat_obj->add_category($_POST['cat_title']);
    
	if ($result) {
    	header("Location: admin/category.php");
    	exit;
    else {
        echo "Oops, something went wrong";
    }
}

of course something in return true or something like that needs to be in the add_category.

 

If require "header.php" is causing the problem then maybe the above needs to be in a configuration file or sessions needs to be used? As the above then isn't at the level at should be at.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.