Headers already sent and session error

Im getting following error in live server, when user login, is sent to dashboard.
warning:session_start():cannot start session when headers already sent in … on line 3

warning:cannot modify header information-header already sent by(output started at…)in…on line 5

login.php code

//No-white-space
<?php
ob_start();
session_start();
?>
if(isset($_POST['login'])){
        $username = $_POST['username'];
        $password = $_POST['password'];
        try {
            $data = $conn->prepare("SELECT * FROM users WHERE username = :username");
            $data->bindParam(':username', $username, PDO::PARAM_STR); 
            $data->execute();
        } catch (PDOException $e) {
            $e->getMessage();
            die("Something went wrong please contact your adminstrator");
        }
         while($rows = $data->fetch(PDO::FETCH_OBJ) ){
           $user_id = $rows->user_id;
           $db_username = $rows->username;
           $db_password = $rows->password;
           $db_user_role = $rows->user_role;
           $db_user_image = $rows->user_image;
         }
         $verifyPassword = password_verify($password, $db_password );
         if($username === $db_username && $verifyPassword){
            $_SESSION['username'] = $db_username;
            $_SESSION['user_role'] =  $db_user_role;
            $_SESSION['user_image'] =  $db_user_image;
            $_SESSION['message'] = '';
            $_SESSION['IS_LOGIN']='yes';

            header('Location:admin');
        }else{
            //header('Location:index.php');
            echo "<script>alert('Invalid Paswword')</script>";
        }
    }

After successful login its redirect to dashboard
im getting error in this page.
warning:session_start():cannot start session when headers already sent in … on line 3
warning:cannot modify header information-header already sent by(output started at…)in…on line 5

<?php
ob_start();
session_start();//line 3
if(!isset($_SESSION['user_role'])){
header('Location:../index.php');//line 5
}
?>
<!DOCTYPE html>
<html lang="en">
<head>

what im doing wrong…

The most important information, which line the output is occurring on, you left out.

However, if it’s line 1, and the <?php tag is what is on line one in the file, the problem is most likely your programming editor has saved the file with Byte Order Mark (BOM) characters. If so, the solution is to change the character settings in your programming editor to save the file without the BOM.

If you added the ob_start() statements as an attempt to make this error go-away, remove them. Trying to hide errors doesn’t fix the problem, it just hides the problem.

This code contains about three times too many php statements and it is missing two important features, trimming, then validating data before using it. The only things that it is doing that should be kept are - using the PDO extension, using a prepared query, and using password_verify(). Everything else is either unnecessary typing or is actually problematic in a web application. If I/others have time they will post a list of do’s and don’ts the will simplify all this code and get it to provide a good user experience.

.

1 Like

Do you see a problem here?

Additionally, you should not need ob_start(); and stop creating variables for nothing. You need to kill the script after a header redirect or the code will keep running.

1 Like

You need to kill the script after a header redirect or the code will keep running.

can please elaborate… how to kill

ob_start();
session_start();
if(!isset($_SESSION['user_role'])){
header('Location:../index.php');
}
ob_end_clean()

adding ob_end_clean() errors are gone to more errors, sorting_order its generating erros

<?php
    $child_data= $conn->query("SELECT * FROM children_page WHERE parent_id = $rows->id ORDER BY reorder");
    while($child_rows = $child_data->fetch(PDO::FETCH_OBJ) ):
?>
<!-- div-wrapper -->
<?php 
// taking user input to update sorting order for child page on reorder column in database
    if(isset($_POST['reorder'])){
      $id_reorder      = $_POST['reorder_id'];
      $reoder_value  = $_POST['reoder_value'];
      $update  = $conn->prepare("UPDATE children_page SET reorder = :reorder WHERE child_id = :id ");
      $update->execute([
          ":id"=>$id_reorder,
          ":reorder"=>$reoder_value
      ]);
      header("Location:index.php");
    }  
?>

<!-- taking input from user for sorting the order of child page -->
 <form action="" method="post">
    <td scope="col">
      <input type="hidden" name="reorder_id" value="<?php echo $child_rows->child_id;?>">

      <input size="1" type="text" class="reorder-size text-center" name="reoder_value" value="<?php echo $child_rows->reorder;?>">
      <input type="submit" value="Update" name="reorder">
    </td>
</form>

While click on update button… for sorting order in reorder column its throwing errors:

Warning: Cannot modify header information - headers already sent by (output started at
what could the possible reason… for this error

All that did is buffer and then delete the php error messages that were produced. It didn’t stop the output that is occurring that is preventing the session_start and header statements from working. Delete the ob_start and ob_end_clean statements, they are not fixing anything, just hiding problems.

Here’s a laundry list of do’s and don’ts, repeats those that @benanamen has given -

  1. Don’t use output buffering unless you intentionally want to buffer output. Don’t use it to try to make bad code run. Find and fix whatever is causing the code to not run.
  2. If the current user is already logged in, they should not be allowed to access the login form/form processing code.
  3. Don’t attempt to detect if a submit button is set. There are times when it won’t be. Instead, detect if a post method form as been submitted.
  4. Don’t copy variables to other variables for nothing. This is just a waste of your time typing. Instead, keep the submitted form data as a set in an array variable, then operate on elements in this array variable through the rest of the code.
  5. Once you do item #4, you can trim all the input data at once, using a single php statement.
  6. Validate all inputs, storing user/validation errors in an array using the field name as the array index.
  7. After the end of all the validation logic, if the array holding the errors is empty, use the submitted data.
  8. If you build the sql query statement in a php variable it makes debugging easier and you will also see common sets of code dealing with queries that can then be converted to classes/functions.
  9. List out the columns you are SELECTing in a query.
  10. Simple ? positional prepared query place-holder save a bunch of typing and typo mistakes.
  11. If you name the db connection variable $pdo, anyone looking at the code will know which database extension is being used.
  12. Use implicit binding by simply supplying an array of the input data to the ->execute([…]) call.
  13. Except for inserting/updating duplicate or out of range user submitted data, there’s nothing the visitor to a site can do about a database statement error. Do not waste time setting up cute messages. The error handling you have should already be logging database statement errors, in which case the site owner will already know that errors are occurring. The way to do this is to simply let php catch the database exceptions, where php will use its error related settings to control what happens with the actual error information (database statement errors will ‘automatically’ get displayed/logged the same as php errors.)
  14. Don’t use a loop to fetch data from a query that will at most match one row of data, just directly fetch/test the fetched data.
  15. When you make the database connection, set the default fetch mode to assoc, so that you don’t need to specify it in each fetch statement. Using an array for data is more conducive to dynamically processing data.
  16. There’s no need to compare the submitted username with the value fetched from the query. You know that if the query matched a row, that the WHERE clause was true.
  17. Don’t tell the visitor which of the username or password didn’t match. Output one generic message for both. If you want to know which values are causing failed login attempts, log that information to a file or a database table.
  18. The only value that you should store in a session variable is the user id (autoincrement primary index) to indicate WHO the logged in user is. You should query on each page request to get any other user information. This is so that any changes made to the user information will take effect on the very next page request.
  19. Upon successful completion of the post method form processing code, you should redirect to the exact same url of the current page to cause a get request for that page. This prevents the browser from trying to resubmit the form data should the user reload the page or browse away from and back to the page. To allow the user to go to any other page, provide navigation links.
  20. Every redirect needs an exit/die statement after it to stop php code execution.
  21. If you want to display a one-time success message, store it in a session variable, then test, display, and clear the session variable at the appropriate location in the html document.
  22. If there are errors at item #7 in this list, the code would continue on to display the html document, display any errors, redisplay the form, populating the form field values with the submitted form data, so that the user doesn’t need to keep reentering data over and over.
  23. Any dynamic value that you output on a web page should have htmlentities applied to it to help prevent cross site scripting.

See item #20 in the above list.

1 Like

It’s the same problem at the start of this thread. If you are not looking at and reading the error message to see where the output is occurring at and are not posting that part of the error message, we cannot help you.

after adding ob_start() and ob_end_clean() working fine no more errors but is it right way…???

<?php
ob_start();
if(isset($_POST['reorder'])){
      $id_reorder      = $_POST['reorder_id'];
      $reoder_value  = $_POST['reoder_value'];
      $update  = $conn->prepare("UPDATE children_page SET reorder = :reorder WHERE child_id = :id ");
      $update->execute([
          ":id"=>$id_reorder,
          ":reorder"=>$reoder_value
      ]);
      header("Location:index.php");
    }
ob_end_clean();

No. Please read the replies you have already gotten.

Your login check code is not working and because there’s no exit/die statement after the redirect to stop php code execution, anyone, logged in or not, having a user_role value or not, can access the page.