I'm developing a web service on PHP where I use the standard PHP SoapServer class with a WSDL file provided by my client, but I also need to use output buffering to "tidy up" the SOAP response that PHP produces (adding some missing namespaces, adding xmlns=""
to a few tags and other small but necessary details).
The problem is that when I use explicit output buffering (ob_start()
, ob_end_flush()
...), any outbound message from my server gets truncated, whatever its size (I'm testing in the range of about 2KB-50KB). When I don't use explicit output buffering, the client gets the complete SOAP response, but as those details I mentioned haven't been fixed, the format isn't quite right.
Here's the code of my server:
if (!extension_loaded("soap")) {
dl("php_soap.dll");
}
//Disable wsdl caching
ini_set("soap.wsdl_cache_enabled", "0");
//Get SOAP message from client
$input_msg = file_get_contents("php://input");
//Create SoapServer object with url to the .wsdl file
$server = new SoapServer(WSDL_FILE_URL, array('encoding' => 'UTF-8', 'actor' => SERVER_URL));
//Set the class that will handle every possible request form the client
$server->setClass("ServerHandler",$input_msg);
//Before I let the server handle the request and return the response to the client,
//I turn on output buffering so I can fix its format
ob_start(NULL, 1<<20);
$server->handle(); //let the server handle the request and write the response to the buffer
$soapXml = ob_get_contents(); //I get the response from the output buffer
ob_end_clean(); //clear the output buffer of its content
//this function does all those small format fixes to the SOAP response that PHP produces
$soapXml=fixSoapResponseFormat($soapXml);
echo $soapXml;//put the correct SOAP response in the output buffer
ob_end_flush();//flush the output buffer and turn off buffering
flush();//this supossedly flushes lower level buffers, just in case
As you can see, I've tried using a high value for the $chunk_size
parameter of ob_start()
, and adding flush()
after ob_end_flush()
, just in case. I've also tried setting output_buffering = On
on php.ini (which supposedly enables an unlimited output buffer) and setting LimitRequestFieldSize
and LimitRequestLine
to 5500000 on Apache, but to no avail.
I've tried dumping to disk the contents of $soapXml
after flushing the buffer, and the message is complete, so I guess the problem must be in the echo $soapXml;
line or in the flushing of the buffer right after it.
I'm using Apache with PHP 5.3 to run the server and SoapUI 5 as a client to test it. I'm also using WS-Security in all communications between server and client (in case it's relevant).
Does anyone know how to solve this problem with the buffering of SOAP messages? Maybe there's another way to catch and modify the SOAP response that PHP produces before it's sent to the client? I'd be grateful for any advice.
Apparently, the problem was that I was letting PHP generate a SOAP message with its http header in the $server->handle();
line, but then I was capturing it in the buffer and changing its size without updating the Content-Length
http header, so the message was sent, but got truncated to its original size.
So here's the properly working code:
if (!extension_loaded("soap")) {
dl("php_soap.dll");
}
//Disable wsdl caching
ini_set("soap.wsdl_cache_enabled", "0");
//Get SOAP message from client
$input_msg = file_get_contents("php://input");
//Create SoapServer object with url to the .wsdl file
$server = new SoapServer(WSDL_FILE_URL, array('encoding' => 'UTF-8', 'actor' => SERVER_URL));
//Set the class that will handle every possible request form the client
$server->setClass("ServerHandler",$input_msg);
//Before I let the server handle the request and return the response to the client,
//I turn on output buffering so I can fix its format
ob_start(NULL, 1<<20);
$server->handle(); //let the server handle the request and write the response to the buffer
$soapXml = ob_get_contents(); //I get the response from the output buffer
ob_end_clean(); //clear the output buffer of its content
//this function does all those small format fixes to the SOAP response that PHP produces
$soapXml=fixSoapResponseFormat($soapXml);
header('Content-Length: '.strlen($soapXml));//**UPDATE THE LENGTH HEADER**
echo $soapXml;//put the correct SOAP response in the output buffer
ob_end_flush();//flush the output buffer and turn off buffering
flush();//this supossedly flushes lower level buffers, just in case
Many thanks to Valentin Rodygin for his great help in finding the source of my troubles!