PHP:警告:session_regenerate_id():无法重新生成会话ID - 已发送的标头

时间:2016-03-23 15:01:24

标签: php session

显然,我不是唯一遇到此问题的人。但是,我无法根据我发现的与此错误消息相关的其他用户发布来修复它。

我收到以下错误:

( ! ) Warning: session_regenerate_id(): Cannot regenerate session id - headers already sent in C:\wamp\www\Creating-Secure-PHP-Websites\05_authentication\sample_app\private\functions\session_hijacking_functions.php on line 113
Call Stack
#   Time    Memory  Function    Location
1   0.0000  244440  {main}( )   ..\login.php:0
2   0.0830  322816  after_successful_login( )   ..\login.php:33
3   0.0830  322864  session_regenerate_id ( )   ..\session_hijacking_functions.php:113

( ! ) Warning: Cannot modify header information - headers already sent by (output started at C:\wamp\www\Creating-Secure-PHP-Websites\05_authentication\sample_app\public\login.php:3) in C:\wamp\www\Creating-Secure-PHP-Websites\05_authentication\sample_app\private\functions\general_functions.php on line 7
Call Stack
#   Time    Memory  Function    Location
1   0.0000  244440  {main}( )   ..\login.php:0
2   0.0990  323120  redirect_to( )  ..\login.php:34
3   0.0990  323256  header ( )  ..\general_functions.php:7

的login.php:

<?php require_once("../private/initialize.php"); ?>

<?php

// Rather than require setting up a real database, 
// we can fake one instead.
initialize_fake_database();

// initialize variables to default values
$username = "";
$password = "";
$message = "";

if(request_is_post() && request_is_same_domain()) {

  if(!csrf_token_is_valid() || !csrf_token_is_recent()) {
    $message = "Sorry, request was not valid.";
  } else {
    // CSRF tests passed--form was created by us recently.

        // retrieve the values submitted via the form
    $username = $_POST['username'];
    $password = $_POST['password'];

        if(has_presence($username) && has_presence($password)) {

            // Search our fake database to retrieve the user data
            $sqlsafe_username = sql_prep($username);
            $user = find_one_in_fake_db('users', 'username', $sqlsafe_username);

        if($user && password_verify($password, $user['hashed_password'])) {
            // successful login
          after_successful_login();
          redirect_to('private.php');
        } else {
          // failed login
          $message = "Username/password combination not found.";
        }

        } else {
            // username or password left blank, just re-display the form.
        }
  }
}

?>

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Log in</title>
  </head>
  <body>

    <?php
      if($message != "") {
        echo '<p>' . h($message) . '</p>';
      }
    ?>

    <p>Please log in.</p>

    <form action="login.php" method="POST" accept-charset="utf-8">
      <?php echo csrf_token_tag(); ?>
      Username: <input type="text" name="username" value="<?php echo h($username); ?>" /><br />
            <br />
      Password: <input type="password" name="password" value="" /><br />
            <br />
      <input type="submit" name="submit" value="Log in" />
    </form>

<?php
// Uncomment if you want to examine the contents of the fake database
// echo "<br /><br />";
// echo "--- fake database contents ---";
// var_dump($_SESSION['fake_database']);
// echo "------------------------------";
?>
  </body>
</html>

general_functions.php:

<?php
// Put all of your general functions in this file

// header redirection often requires output buffering 
// to be turned on in php.ini.
function redirect_to($new_location) {
  header("Location: " . $new_location);
  exit;
}

?>

session_hijacking.php:

<?php
// Useful php.ini file settings:
// session.cookie_lifetime = 0
// session.cookie_secure = 1
// session.cookie_httponly = 1
// session.use_only_cookies = 1
// session.entropy_file = "/dev/urandom"

// Must have already called:
// session_start();

// Function to forcibly end the session
function end_session() {
    // Use both for compatibility with all browsers
    // and all versions of PHP.
    session_unset();
  session_destroy();
}

// Does the request IP match the stored value?
function request_ip_matches_session() {
    // return false if either value is not set
    if(!isset($_SESSION['ip']) || !isset($_SERVER['REMOTE_ADDR'])) {
        return false;
    }
    if($_SESSION['ip'] === $_SERVER['REMOTE_ADDR']) {
        return true;
    } else {
        return false;
    }
}

// Does the request user agent match the stored value?
function request_user_agent_matches_session() {
    // return false if either value is not set
    if(!isset($_SESSION['user_agent']) || !isset($_SERVER['HTTP_USER_AGENT'])) {
        return false;
    }
    if($_SESSION['user_agent'] === $_SERVER['HTTP_USER_AGENT']) {
        return true;
    } else {
        return false;
    }
}

// Has too much time passed since the last login?
function last_login_is_recent() {
    $max_elapsed = 60 * 60 * 24; // 1 day
    // return false if value is not set
    if(!isset($_SESSION['last_login'])) {
        return false;
    }
    if(($_SESSION['last_login'] + $max_elapsed) >= time()) {
        return true;
    } else {
        return false;
    }
}

// Should the session be considered valid?
function is_session_valid() {
    $check_ip = true;
    $check_user_agent = true;
    $check_last_login = true;

    if($check_ip && !request_ip_matches_session()) {
        return false;
    }
    if($check_user_agent && !request_user_agent_matches_session()) {
        return false;
    }
    if($check_last_login && !last_login_is_recent()) {
        return false;
    }
    return true;
}

// If session is not valid, end and redirect to login page.
function confirm_session_is_valid() {
    if(!is_session_valid()) {
        end_session();
        // Note that header redirection requires output buffering 
        // to be turned on or requires nothing has been output 
        // (not even whitespace).
        header("Location: login.php");
        exit;
    }
}


// Is user logged in already?
function is_logged_in() {
    return (isset($_SESSION['logged_in']) && $_SESSION['logged_in']);
}

// If user is not logged in, end and redirect to login page.
function confirm_user_logged_in() {
    if(!is_logged_in()) {
        end_session();
        // Note that header redirection requires output buffering 
        // to be turned on or requires nothing has been output 
        // (not even whitespace).
        header("Location: login.php");
        exit;
    }
}


// Actions to preform after every successful login
function after_successful_login() {
    // Regenerate session ID to invalidate the old one.
    // Super important to prevent session hijacking/fixation.
    session_regenerate_id();

    $_SESSION['logged_in'] = true;

    // Save these values in the session, even when checks aren't enabled 
  $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
  $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
    $_SESSION['last_login'] = time();

}

// Actions to preform after every successful logout
function after_successful_logout() {
    $_SESSION['logged_in'] = false;
    end_session();
}

// Actions to preform before giving access to any 
// access-restricted page.
function before_every_protected_page() {
    confirm_user_logged_in();
    confirm_session_is_valid();
}


// Uncomment to demonstrate usage

// if(isset($_GET['action'])) {
//  if($_GET['action'] == "login") {
//      after_successful_login();
//  }
//  if($_GET['action'] == "logout") {
//      after_successful_logout();
//  }
// } 
// 
// echo "Session ID: " . session_id() . "<br />";
// echo "Logged in: " . (is_logged_in() ? 'true' : 'false') . "<br />";
// echo "Session valid: " . (is_session_valid() ? 'true' : 'false') . "<br />";
// echo "<br />";
// echo "--- SESSION ---<br />";
// var_dump($_SESSION);
// echo "--------------------<br />";
// echo "<br />";
// 
// echo "<a href=\"?action=new_page\">Simulate a new page request</a><br />";
// echo "<a href=\"?action=login\">Simulate a log in</a><br />";
// echo "<a href=\"?action=logout\">Simulate a log out</a>";

?>

1 个答案:

答案 0 :(得分:1)

快速而肮脏的回答: 在致电session_regenerate_id()之前,请确保不输出任何内容。

当您输出数据时,您将开始提供响应,该响应将发送HTTP响应标头。在发送之后,您无法更改HTTP标头(重新生成会话cookie ID)。

查看您的脚本,您应该删除第3行的第一个php结束标记?>和开头标记<?php

的login.php:

<?php require_once("../private/initialize.php");


// Rather than require setting up a real database, 
// we can fake one instead.
initialize_fake_database();

为什么会这样? 如果.php脚本直接输出HTML,PHP会将<?php ?>标记之外的所有内容视为输出。即使使用新行启动文件也会产生输出,并且当您想要设置HTTP响应标头时会导致错误。

要迁移它,您可以考虑在.php文件中使用仅PHP,并通过模板输出您的html。这将是使用框架的第一步,无论如何我都会建议。