PHP Conference Japan 2024

SoapServer::handle

(PHP 5, PHP 7, PHP 8)

SoapServer::handle处理 SOAP 请求

描述

public SoapServer::handle(?string $request = null): void

处理 SOAP 请求,调用必要的函数,并发送响应。

参数

request

SOAP 请求。如果省略此参数,则假定请求位于 HTTP 请求的原始 POST 数据中。

返回值

不返回值。

变更日志

版本 描述
8.0.0 request 现在可以为 null。

示例

示例 #1 SoapServer::handle() 示例

<?php
function test($x)
{
return
$x;
}

$server = new SoapServer(null, array('uri' => "http://test-uri/"));
$server->addFunction("test");
$server->handle();
?>

参见

添加注释

用户贡献的注释 8 条注释

dub357 at gmail dot com
12 年前
经过多次头痛和查看 PHP 源代码后,我终于找到了为什么 handle() 函数会立即返回带有字符串“错误请求”的错误的原因。
事实证明,我的客户端发送了有效的 XML,但 XML 的第一行是实际的 XML 声明

<?xml version="1.0" encoding="UTF-8"?>

当调用 SoapServer 类中的“handle”函数时,它首先尝试解析 XML。当 XML 文档无法解析时,会返回“错误请求”错误,并且脚本的执行会立即停止。我假设 PHP 中内置的 XML 解析器 (libxml2) 已经假设文档为 XML,并且当它找到声明时,它认为它无效。

在调用 handle() 函数之前,我在我的服务中添加了一些 XML 解析调用以检查有效的 XML 并避免“错误请求”错误。这还允许我发送更合适的错误消息

<?php
$parser
= xml_parser_create("UTF-8");
if (!
xml_parse($parser,$HTTP_RAW_POST_DATA,true)){
$webService->fault("500", "Cannot parse XML: ".
xml_error_string(xml_get_error_code($parser)).
" at line: ".xml_get_current_line_number($parser).
", column: ".xml_get_current_column_number($parser));
}
?>
Bas van Dorst
10 年前
"Joeri Thissen" 评论的补充信息 (https://php.net/manual/en/soapserver.handle.php#113866)

在某些情况下,替换会生成超时(看起来它与 Nginx 结合使用)。问题是 PHP 已经发送了内容长度,并且 Web 服务器仍在等待新内容。

要解决此问题,您必须使用正确的值重置 HTTP 内容长度

<?php
ob_start
();
$soapServer->handle();
$result = ob_get_contents();
ob_end_clean();

$result = str_replace("abcdef", "abc", $result);
$length = strlen($result);

header("Content-Length: ".$length);
echo
$result;
Joeri Thissen
10 年前
有时返回的数据可能包含在 xml 1.0 中无效的字符。这会导致 SoapServer::handle 输出的 xml 无效。尽管最好在早期对数据进行清理,但输出缓冲和简单的正则表达式组合可以用作快速修复,以确保输出确实是有效的 xml。

例如

<?php
ob_start
();
$soapServer->handle();
$soapXml = ob_get_contents();
ob_end_clean();
$soapXml = preg_replace ('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $soapXml);
echo
$soapXml;
?>
Artur Graniszewski
15 年前
请注意,SoapServer::handle(); 方法会向浏览器发送其他 HTTP 标头。其中之一是“Content-Type: application/soap+xml”。如果您想在本地执行 SOAP 方法作为 SoapClient::__doRequest() 的一部分(请参阅 http://pl2.php.net/manual/en/soapclient.dorequest.php 中的示例),您可能需要将此标头重置(覆盖)回“Content-Type: text/html”,如下所示

<?php
function Add($x,$y) {
return
$x+$y;
}

class
LocalSoapClient extends SoapClient {

function
__construct($wsdl, $options) {
parent::__construct($wsdl, $options);
$this->server = new SoapServer($wsdl, $options);
$this->server->addFunction('Add');
}

function
__doRequest($request, $location, $action, $version) {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();
ob_end_clean();
return
$response;
}

}

$x = new LocalSoapClient(NULL,array('location'=>'test://',
'uri'=>'http://testuri.org'));

header("Content-Type: text/html");

var_dump($x->Add(3,4));

?>
[email protected]
16年前
一旦找到解决方案,似乎非常合乎逻辑,但我花了相当长的时间才弄清楚这一点
如果您使用基于 WSDL 的 SOAP 请求,并且您的绑定中有多个操作(具有相同的参数),请确保 <soap:operation> 样式设置为 rpc,而不是 body!

当您在此处指定“body”时,请求中传输的将只是函数调用的参数,并且 SoapServer->handle() 将使用它找到的第一个具有相同参数结构的函数来处理调用。

例如,如果您有两个函数
<?php
function One ( string $blah );
function
Two ( string $blah );
?>
使用 SoapClient -> Two ( 'test' ); 进行客户端调用时,当您的“type”设置为“body”时,将导致调用 One ( )

只有当您的类型设置为“rpc”时,才会将实际调用的方法包含在请求中,从而产生预期的行为
[email protected]
12 年前
请注意,当在一个 wsdl 文件中定义多个服务并调用其中一项服务时,您可能始终会收到第一项服务的响应。

这是一个已知的错误。您可以在此处找到其描述和一些解决方法:https://bugs.php.net/bug.php?id=49169
[email protected]
2个月前
handle 方法捕获致命错误(例如调用未定义的函数),因此它们永远不会进入由 register_shutdown_function、set_error_handler 或 set_exception_handler 注册的函数的日志文件。

此示例不会记录任何内容
<?php
function testFatal($name) {
fhdkshfkhhf();
}

$server = new SoapServer('https://example.com/soap.wsld');
$server->addFunction('testFatal');
$server->handle();
?>

要记录错误,您需要捕获 Throwable
<?php
function testFatal($name) {
try {
fhdkshfkhhf();
} catch (
Throwable $e) {
error_log("SOAP Error: " . $e->getMessage() . "\nStack trace:\n" . $e->getTraceAsString());
throw
$e;
}
}

$server = new SoapServer('https://example.com/soap.wsld');
$server->addFunction('testFatal');
$server->handle();
?>
[email protected]
16年前
回复 Blizzke

有时,此问题可能会被 Apache 分段错误以及抛给客户端的 HTTP 标头错误 SoapFault 隐藏。

如果您遇到这两个错误中的任何一个,请尝试检查以确保 WSDL 文件的 soap:operation 中的 style="rpc"。

-T
To Top