php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #17419 Complex objects not correctly stored in ssession
Submitted: 2002-05-24 16:47 UTC Modified: 2004-09-22 10:32 UTC
Votes:5
Avg. Score:5.0 ± 0.0
Reproduced:4 of 4 (100.0%)
Same Version:3 (75.0%)
Same OS:1 (25.0%)
From: wdseelig at ncms dot org Assigned:
Status: Closed Package: Documentation problem
PHP Version: 4.2.1 OS: BSDi
Private report: No CVE-ID: None
 [2002-05-24 16:47 UTC] wdseelig at ncms dot org
Complex objects are not correctly stored in a session.  This report is similar to 8676, which was reported fixed.  It now appears to be broken in 4.2.1.
Here is a code scriplet to demonstrate the problem:

<?

class Alpha
{
	var $alpha1;
	var $betavar;
	function Alpha()
	{
		$this->betavar =& new Beta(&$this);	//Let Beta use Alpha's methods and properties
		$this->alpha1 = 22;
	}
	function getvar()
	{
		return $this->alpha1;
	}
}
class Beta
{
	var $beta1;
	var $alphacall;
	function Beta(&$par)
	{
		$this->alphacall = &$par;		//alphacall will let Beta use Alpha's methods and properties
		$this->beta1 = 5;
	}
	function getalphavar()
	{
		print("<br>The value of the alphavar from within Beta is:  " . $this->alphacall->alpha1 );
	}
}
session_start();
if  (! session_is_registered("pm")  )
{
	session_register("pm");		// register and instantiate the variable
	$pm =& new Alpha();
}
	print("<br>The vaue of alpha1 is:  " . $pm->getvar()  );
	print("<br>The value of beta1 is:  " . $pm->betavar->beta1);
	print("<br>" . $pm->betavar->getalphavar() );


?>

OBSERVED BEHAVIOR:

When this page is loaded the first time, everything works as expected, and the
values of alpha1, and beta 1 print out just fine. However, attempts
to refresh the page yield a browser error message "This page cannot be displayed".

This structure worked (flakily) on 4.04pi1, and I was hoping that the fix of 8676 would
have made it solid in 4.2.1.  However, the situation is now worse--the above structure
NEVER works.


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-05-25 04:41 UTC] sander@php.net
Can you gice us some real error message instead of the junk you're browser is giving you? Can you try to telnet'ing manually to your webserver and give us the HTTP response?

Also, Apache is not an OS. Please update the field above.
 [2002-05-26 08:20 UTC] wdseelig at ncms dot org
I am developing on a web server to which I do not normally have telnet privileges, but I will ask them if they can open this up to me.

I apologize for putting Apache rather than the OS.  I'll get that for you as soon as I can -- it is BSD something.

Thank you for looking at this!

Wyckham
 [2002-05-26 12:04 UTC] sander@php.net
You don't need telnet access for this. Just telnet from your local box to the webserver, i.e. 
telnet www.yourdomain.com 80
Alternatively, post an url of that page here (or mail it me, if you prefer to keep it private) and I'll see what I can do.
 [2002-05-26 22:13 UTC] wdseelig at ncms dot org
OK -- I have tried to telnet to the domain and cannot do that either.  Here is the URL:

http://sql.wash-gop.com/wyck/WebSiteII/html/simpleclass.php
 [2002-05-29 10:11 UTC] wdseelig at ncms dot org
The correct operating system if BSDi 4.3
 [2002-05-31 09:44 UTC] kalowsky@php.net
Your example works fine on my FreeBSD 4.5 system using PHP 4.2.1.  

Also updated your OS to BSDi instead of Apache.
 [2002-05-31 09:51 UTC] kalowsky@php.net
Also worked fine on my OSX boxen.

I don't know what browser you are using so I can't comment on the validity of that error message (possible MSIE pretty error page?).

One thing to try, turn on your register_globals.  Your example kind of needs that, or different calling methods.
 [2002-06-01 06:14 UTC] sander@php.net
Consider the following sample script:

<?php
session_start();
class alpha {
	var $b;	
	function alpha() {
		$this->b = &new beta(&$this);
	}
}

class beta {
	function beta($t) {
		$this->t = &$t;
	}
}

if($_GET['set']) {
	$_SESSION['a'] = &new alpha();
} else {
	print_r($_SESSION['a']);
}
?>

First, call this script with ?set=1.
Then, call it without any arguments and nothing will happen. The connection will close inmediately:
$ telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /test.php?PHPSESSID=dcfffa113d892c4320d6109c6bd07795 HTTP/1.1
Host: localhost

Connection closed by foreign host.

This was exactly what happend with the sample simpleclass.php script provided by wseelig@ncms.org

Apache logs show a couple of memleaks and a segfault:
home/sander/php/head/Zend/zend_hash.c(262) :  Freeing 0x0821CD4C (37 bytes), script=/home/sander/public_html/test.php
Last leak repeated 1 time
/home/sander/php/head/Zend/zend_hash.c(178) :  Freeing 0x0821B1BC (32 bytes), script=/home/sander/public_html/test.php
Last leak repeated 1 time
/home/sander/php/head/Zend/zend_API.c(597) :  Freeing 0x0821B15C (44 bytes), script=/home/sander/public_html/test.php
/home/sander/php/head/Zend/zend_API.c(585) : Actual location (location was relayed)
Last leak repeated 1 time
/home/sander/php/head/Zend/zend_execute.c(1937) :  Freeing 0x0821B11C (12 bytes), script=/home/sander/public_html/test.php
Last leak repeated 1 time
/home/rasmus/php4/ext/standard/url_scanner_ex.re(409) :  Freeing 0x08219B6C (13 bytes), script=/home/sander/public_html/test.php
[Sat Jun  1 12:06:13 2002] [notice] child pid 4079 exit signal Segmentation fault (11)

Backtrace:
Program received signal SIGSEGV, Segmentation fault.
0x4010cf96 in malloc () from /lib/libc.so.6
(gdb) bt
#0  0x4010cf96 in malloc () from /lib/libc.so.6
#1  0x403d9a4f in _emalloc (size=35, 
    __zend_filename=0x404b0c80 "/home/sander/php/head/Zend/zend_hash.c", 
    __zend_lineno=406, __zend_orig_filename=0x0, __zend_orig_lineno=0)
    at /home/sander/php/head/Zend/zend_alloc.c:165
#2  0x403f46cc in zend_hash_index_update_or_next_insert (ht=0xbfffef34, 
    h=23815, pData=0xbf800108, nDataSize=4, pDest=0x0, flag=4)
    at /home/sander/php/head/Zend/zend_hash.c:406
#3  0x4038f81a in php_add_var_hash (var_hash=0xbfffef34, var=0x8219b9c, 
    var_old=0xbf800264) at /home/sander/php/head/ext/standard/var.c:393
#4  0x4038ed6e in php_var_serialize_intern (buf=0xbfffef60, struc=0x8219b10, 
    var_hash=0xbfffef34) at /home/sander/php/head/ext/standard/var.c:497
#5  0x4038f277 in php_var_serialize_intern (buf=0xbfffef60, struc=0x8219d00, 
    var_hash=0xbfffef34) at /home/sander/php/head/ext/standard/var.c:606
#6  0x4038f277 in php_var_serialize_intern (buf=0xbfffef60, struc=0x8219b10, 
    var_hash=0xbfffef34) at /home/sander/php/head/ext/standard/var.c:606
#7  0x4038f277 in php_var_serialize_intern (buf=0xbfffef60, struc=0x8219d00, 
    var_hash=0xbfffef34) at /home/sander/php/head/ext/standard/var.c:606
#8  0x4038f277 in php_var_serialize_intern (buf=0xbfffef60, struc=0x8219b10, 
    var_hash=0xbfffef34) at /home/sander/php/head/ext/standard/var.c:606
#9  0x4038f277 in php_var_serialize_intern (buf=0xbfffef60, struc=0x8219d00, 
    var_hash=0xbfffef34) at /home/sander/php/head/ext/standard/var.c:606
etc etc etc
 [2002-06-01 06:19 UTC] mfischer@php.net
Circular references don't work with the serializer
 [2002-06-01 06:43 UTC] mfischer@php.net
I checked back with Zeev, circular references are simlpy not supported in the Zend engine and won't be anytime soon.
 [2002-06-01 07:03 UTC] sander@php.net
Suspending.
 [2002-06-01 07:12 UTC] sander@php.net
Reclassified as a documentation problem after a nice discussion with Markus :)
 [2002-12-13 11:01 UTC] philip@php.net
Please further explain what circular references are so this can be documented.
 [2002-12-13 11:02 UTC] philip@php.net
This one is related too:
http://bugs.php.net/bug.php?id=14645

 [2003-01-04 12:08 UTC] wdseelig at ncms dot org
My apologies for taking so long to respond.  The Christmas season intervened.  Here is an answer to the question:

THE BASICS

A circular reference occurrs when an object passes a reference to itself to another object.

Imagine a script in which an object of one class instantiates an object of another class.  Call the
first object the "parent" and the second object the "child".  What happens if the parent object passes
a reference to itself to the child object?  Could the child object then use this reference to access
the methods and properties of the parent object? The code would look something like this:

<?
class Parent
{
	var $childvar;
	var $parentvar;
	function Parent()
	{
		$this->childvar =& new Child(&$this);
		$this->parentvar = 22;
	}	

}
class Child
{
	var $parentcall;
	function Child(&$par)
	{
		$this->parentcall = &$par;	
	}
	function getparentvar()
	{
		print("<br>The value of the parent variable from within the child is" . $this->parentcall->parentvar;
	}
}

>?

Note that the parent passes a reference to itself to the child which then stores this reference in a variable
called $parentcall.  When the child function getparentvar is called, the child uses the stored reference to its
parent to access a property ($parentvar) of the parent.

Will this work?

The answer is yes, BUT.  The "yes" is that if you run this code it will work fine.  The "BUT" is that if you
ask PHP's serializer to reconstruct this structure, it will NOT work.


What happens, in other words, if you add to the above script code that looks like this:

<?

	if ( ! session_is_registered("sess")  )// Create a session variable to store parent and child
		{
			session_register("sess");
			$sess = new Parent();
		}
	print ("The vaue of parentvar from within the child is:  " . $sess->childvar->getparentvar());

?>

Answer:  the the first time that you run this, it will work fine.  HOWEVER, if you try to refresh your browser
screen, PHP uses its seralizer to reconstruct the $sess variable and is unable to do so.  As a consequence,
you will get error messages, and, in some cases, PHP will crash.

The reason is that the serializer considers this structure to be a circular reference [the child class is
referencing the parent] and is not able to handle such constructs.

A FURTHER EXPLANATION

Why would one try to create a Parent/Child structure like that outline above?  Perhaps a brief explanation of
what I was trying to do will shed further light on the issue.

In my case, the "parent" class was a page manager, and was responsible for sending html to the browser.
The child classes were a connection manager and a recordset manager.  I wanted all of the classes: the page
manager, the connection manager, and the recordset manager, to have access to a set of common error
handling routines.  So, in my first attempt, I included all of the error handling machinery in the page
manager class, and passed a reference to the page manager class down to the connection and recordset manager
classes.  [Much like the Parent/Child code above].

When this didn't work, I removed the error handling code from the page manager class, and created a new 
error handling class.  However, I did not want each object to insantiate its own error object, so I was
still confronted with the problem of letting the recordset and connection objects know where the error object
was.  The solution to this dilemma was to instantiate error, recordset manager, and connection objects in the
page manager, and then pass a reference to the error object to both the recordset and the connection objects.  

Now this may seem like exactly the same kind of thing that got me in trouble in the first place, but it is
not.  In this case, the reference that is being passed is NOT a reference to the parent, but rather it is
a reference to another child object--and this, for some reason, works just fine.

I don't know how clear this is; if you would like to ask me questions, please feel free to do so.


Wyckham Seelig
 [2004-09-22 10:32 UTC] vrana@php.net
This bug has been fixed in the documentation's XML sources. Since the
online and downloadable versions of the documentation need some time
to get updated, we would like to ask you to be a bit patient.

Thank you for the report, and for helping us make our documentation better.

"Some types of data can not be serialized thus stored in sessions. It includes resource variables or objects with circular references (i.e. objects which passes a reference to itself to another object)."
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Jun 03 05:01:29 2024 UTC