php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #51561 SoapServer with a extented class and using sessions, lost the setPersistence()
Submitted: 2010-04-15 12:50 UTC Modified: 2023-10-29 11:59 UTC
Votes:48
Avg. Score:4.0 ± 0.9
Reproduced:43 of 43 (100.0%)
Same Version:7 (16.3%)
Same OS:14 (32.6%)
From: marciomaianunes at hotmail dot com Assigned: nielsdos (profile)
Status: Closed Package: SOAP related
PHP Version: 5.2.11 OS: Linux 2.6.26
Private report: No CVE-ID: None
 [2010-04-15 12:50 UTC] marciomaianunes at hotmail dot com
Description:
------------
A SoapServer using sessions and extending some class included by require or 
include functions, lose the persistence seted by setPersistence 
(SOAP_PERSISTENCE_SESSION)

The script below will work fine with one of 3 changes (no idea why):

- Declaring the class "Server2" in the same file as class "Server" (Server1.php) 
and removing the require_once(Server2.php);

- Removing the "session_start();" from server.php

- If class "Server" do no extend any class, it also works.

Thanks a lot!


Test script:
---------------
## Client.php ##
<?php 
$cli = new SoapClient(null, array('location' => "http://localhost:81/bugTest/Server.php", 'uri' => "blablabla.com",'encoding' => "ISO-8859-1",'soap_version' => SOAP_1_2));
$cli->setValue(100);
$response = $cli->getValue();
echo "Get = ".$response;	
?>

## Server.php ##
<?php 
session_start();
require_once("Server2.php");
class Server extends Server2 {
	private $value;
	public function setValue($param) { $this->value = $param; }
	public function getValue() { return $this->value; }
}
$server = new SoapServer(null, array('uri' => "blablabla.com",'encoding' => "ISO-8859-1",'soap_version' => SOAP_1_2));
$server->setClass("Server");
$server->setPersistence(SOAP_PERSISTENCE_SESSION);
$server->handle();
?>

## Server2.php ##
<?php class Server2{ private $nothing; } ?>

Expected result:
----------------
Get = 100

Actual result:
--------------
Get = 

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-04-15 12:55 UTC] marciomaianunes at hotmail dot com
-PHP Version: 5.2.13 +PHP Version: 5.2.11
 [2010-04-15 12:55 UTC] marciomaianunes at hotmail dot com
Same error in PHP 5.2.6-1+lenny3
 [2023-10-13 23:44 UTC] nielsdos@php.net
I found the root cause.
When using persistent sessions, the soap server object is put into the session storage.
On the next request, session_start() at the beginning will decode the session object, before the require_once has executed. So that means the soap server object will be decoded before its parent (Server2) has been compiled. This causes the server object to be updated in the session storage to be of class entry PHP_COMPLETE_CLASS. The consequence of this is that the check: `Z_OBJCE_P(tmp_soap_p) == service->soap_class.ce)` will fail, causing the session not to work.

I see two options to fix this:
- Delay deserialization by storing the object as a string. Proof of concept implementation that works here: https://github.com/nielsdos/php-src/pull/52
- Live with this limitation that the session must not be started before the classes are loaded, and emit a warning to the user. I looked into this but the warning is thrown away by the handle() method.
 [2023-10-13 23:45 UTC] nielsdos@php.net
-Status: Open +Status: Verified
 [2023-10-29 11:59 UTC] nielsdos@php.net
-Status: Verified +Status: Closed -Assigned To: +Assigned To: nielsdos
 [2023-10-29 11:59 UTC] nielsdos@php.net
This is mitigated in 8.4-dev: now it throws an error message describing the solution
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 09:01:32 2024 UTC