显然,我不是唯一遇到此问题的人。但是,我无法根据我发现的与此错误消息相关的其他用户发布来修复它。
我收到以下错误:
( ! ) 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>";
?>
答案 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。这将是使用框架的第一步,无论如何我都会建议。