php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #42774 $_SESSION data not written if var populated from function first
Submitted: 2007-09-27 04:10 UTC Modified: 2007-10-01 12:09 UTC
From: johns582 at mail dot msu dot edu Assigned:
Status: Not a bug Package: Session related
PHP Version: 5.2.4 OS: Debian 4.1.1; FreeBSD 4.8
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: johns582 at mail dot msu dot edu
New email:
PHP Version: OS:

 

 [2007-09-27 04:10 UTC] johns582 at mail dot msu dot edu
Description:
------------
We use a function (see below) to populate variables based on whether there is a key present in the $_GET, $_POST, or $_SESSION arrays. After this function is called and the result assigned to a variable, we save the variable in a session with:

$_SESSION['var'] = $var; 

The result of this statement is that the variable $var is successful stored in $_SESSION but is not saved to the session file, which is what we expect. We can correct the problem by taking the logic in the function below out of the function and placing it into the body of the main script. We've also noticed that even when the function is called by the main script, but not used to assign a value to a variable we intend to store in a session, this is enough to "break" the session in the manner described above (e.g.,

//DOESN'T WORK TO MAKE $f_name and $l_name appear in the session file
//even though we aren't actually storing the value of $f_name_p or //$l_name_p in the session. But works if lines 3 and 4 are removed.
$f_name = $_POST['f_name']; 
$l_name = $_POST['l_name']; 
$f_name_p = populate_rev ("f_name", $_GET, $_POST, $_SESSION);
$l_name_p = populate_rev ("l_name", $_GET, $_POST, $_SESSION);
$_SESSION['f_name'] = $f_name; 
$_SESSION['l_name'] = $l_name; 

One last point: This problem occurs with both the default "files" session handler and a custom db-backed handler. Using the db-backed handler, we can confirm that the overloaded "write" function received a session key, but no data.

Reproduce code:
---------------
function populate_rev ($array_index, $_GET, $_POST, $_SESSION) { 
	
	if (isset($_GET["$array_index"])) { 
		$var = $_GET["$array_index"]; 
	}	
	elseif (isset($_POST["$array_index"])) { 
		$var = $_POST["$array_index"]; 
	} 
	elseif (isset($_SESSION["$array_index"])) { 
		$var = $_SESSION["$array_index"]; 
	} 
	else { 
		$var = ''; 
	} 	
	return $var; 
}

Expected result:
----------------
Expected to see the string f_name|s:7:"Heather";l_name|s:7:"Johnson"; present in the session file or in the database (depending on which handler was currently being used), for example, following assignment of $f_name and $l_name to the corresponding key in $_SESSION and termination of the script.

Actual result:
--------------
Even though the $_SESSION array contains the expected key/value pairs, the session file or database row (in the case of our custom handler) doesn't contain them. No data is passed to the session write function in the case of the custom handler. Moving the function's logic into the main body of the script, or abandoning the function in favor of straight assignment from the $_POST vars array is the only way to produce the expected result. (e.g.,

$f_name = $_POST['f_name'];
$l_name = $_POST['l_name'];

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-09-27 09:46 UTC] jani@php.net
Is register_globals=On ?
 [2007-09-27 13:02 UTC] johns582 at mail dot msu dot edu
No, register globals is off. Added note: this code worked in versions of PHP <= 5.0.5
 [2007-09-29 03:02 UTC] jani@php.net
Can you please provide a short but complete reproduce script?
 [2007-09-29 15:17 UTC] johns582 at mail dot msu dot edu
Sure - Here is the form from which the script can be invoked:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
	<title>Test Sessions</title>
</head>
<body>
<form action="/php/test_session.php" method="post">
<input type="text" value="" name="f_name"><br>
<input type="text" value="" name="l_name">
<input type="submit" value="test session">
</form>
</body>
</html>

And here is the script itself (it is currently set up to use a file-based session handler). There is some commented-out code in here that should make it easy to see how seemingly irrelevant adjustments to how the var is initially set will influence whether it gets set in the session file (or db row):

<?php 
	
	//include functions library
	include_once("php/libraries/general_functions_new.php");
	
	session_start();
	
	//if the var assignments are made directly from the _POST array,
	//then the session vars are successfully set
	
	//$f_name = $_POST['f_name']; 
	//$l_name = $_POST['l_name']; 
	
	//but setting the vars with a call to populate_rev, the subsequently
	//assigning them to $_SESSION results in a successful assignment to 
	//$_SESSION, but no storage in the session file or db.
	
	$f_name = populate_rev ("f_name", $_GET, $_POST, $_SESSION);
	$l_name = populate_rev ("l_name", $_GET, $_POST, $_SESSION);
	
	//If code contained in populate_rev is brought into the main 
	//body of this script, then the session vars are successfully set
	/*
	if (isset($_GET["f_name"])) 	{ 
		$f_name = $_GET["f_name"]; 
	}	
	elseif (isset($_POST["f_name"])) { 
		$f_name = $_POST["f_name"]; 
	} 
	else { 
		if (isset($_SESSION["f_name"])) { 
			$f_name = $_SESSION["f_name"]; 
		} 
		else { 
			$f_name = ''; 
		} 
	} 
	
	if (isset($_GET["l_name"])) { 
		$l_name = $_GET["l_name"]; 
	}	
	elseif (isset($_POST["l_name"])) { 
		$l_name = $_POST["l_name"]; 
	} 
	else { 
		if (isset($_SESSION["l_name"])) { 
			$l_name = $_SESSION["l_name"]; 
		} 
		else { 
			$l_name = ''; 
		} 
	} 
	*/
	
	//register vars in the session
	$_SESSION['f_name'] = $f_name; 	
	$_SESSION['l_name'] = $l_name; 
	
	echo "<br>Contents of global _SESSION array: ";
	var_export($_SESSION);
	echo "<br>Done writing session vars. Check session file or db to confirm.";
?>

And here is the function library, general_functions_new.php:

<?php 
	
function populate_rev ($array_index, $_GET, $_POST, $_SESSION) { 
	
	if (isset($_GET["$array_index"])) { 
		$var = $_GET["$array_index"]; 
	}	
	elseif (isset($_POST["$array_index"])) { 
		$var = $_POST["$array_index"]; 
	} 
	elseif (isset($_SESSION["$array_index"])) { 
		$var = $_SESSION["$array_index"]; 
	} 
	else { 
		$var = ''; 
	} 	
	return $var; 
}
?>
 [2007-09-30 06:28 UTC] jani@php.net
And that's the shortest possible script you can reproduce it with?
(I'm pretty sure you can do better.. :)
 [2007-09-30 12:13 UTC] johns582 at mail dot msu dot edu
Here is a version (12 lines) that doesn't have any of the commented out code. But I'd still recommend looking at the original, as the commented code was intended to save you time in reproducing some of the weirder behavior I described above.

<?php 
	include_once("php/libraries/general_functions_new.php");
	
	session_start();
	$f_name = populate_rev ("f_name", $_GET, $_POST, $_SESSION);
	$l_name = populate_rev ("l_name", $_GET, $_POST, $_SESSION);
	$_SESSION['f_name'] = $f_name; 	
	$_SESSION['l_name'] = $l_name; 
	
	echo "<br>Contents of global _SESSION array: ";
	var_export($_SESSION);
	echo "<br>Done writing session vars. Check session file or db to confirm.";
?>
 [2007-09-30 21:35 UTC] jani@php.net
These variables you put in the function definition are super-globals. That means a) they're global everywhere b) you don't need to pass them around. I'd be surprised if this kind of code worked at all..
Please fix your code.
 [2007-10-01 01:19 UTC] johns582 at mail dot msu dot edu
Thanks very much for the input - removing the superglobal arrays from the function definition does fix the problem. This code is about 6 years old and has worked consistently for that entire time period. While it makes complete sense that it is not necessary to pass these arrays as arguments, I'm actually not sure why doing so would cause a problem - seems like it would just be an unnecessary inefficiency. Do you know what changed between versions 5.05 and 5.2.3 that would cause this to break in the manner it does?
 [2007-10-01 12:09 UTC] jani@php.net
No idea what changed but it's most likely related to some engine change and how super-globals are treated. 5.0/5.1 weren't very good releases anyway, lot of stuff got improved and fixed in 5.2 so I wouldn't really  compare these with each other. Anyway, this really isn't any bug per se, hence the bogus status.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 16 21:01:28 2024 UTC