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 現在可為空值。

範例

範例 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() 函式會立即回傳帶有字串「Bad Request」的錯誤。
原來我的用戶端傳送的是有效的 XML,但 XML 的第一行是實際的 XML 宣告

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

當呼叫 SoapServer 類別中的「handle」函式時,它會先嘗試解析 XML。當 XML 文件無法解析時,會回傳「Bad Request」錯誤,並且腳本的執行會立即停止。我假設 PHP 中內建的 XML 解析器 (libxml2) 已經假設文件為 XML,當它找到宣告時,它會認為它無效。

我在呼叫 handle() 函式之前,在我的服務中新增了一些 XML 解析呼叫,以檢查 XML 是否有效並避免「Bad Request」錯誤。這也讓我能夠回傳更合適的錯誤訊息

<?php
$parser
= xml_parser_create("UTF-8");
if (!
xml_parse($parser,$HTTP_RAW_POST_DATA,true)){
$webService->fault("500", "無法解析 XML: ".
xml_error_string(xml_get_error_code($parser)).
" 於第 ".xml_get_current_line_number($parser).
",欄位:".xml_get_current_column_number($parser));
}
?>
Bas van Dorst
10 年前
「Joeri Thissen」的註解的補充資訊 (https://php.dev.org.tw/manual/en/soapserver.handle.php#113866)

在某些情況下,取代會產生逾時 (看起來是與 Nginx 結合使用時)。問題是 PHP 已經傳送了內容長度,而網路伺服器仍在等待新內容。

若要修正此問題,您必須使用正確的值重設 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));

?>
Blizzke at gmail dot com
16 年前
一旦找到解決方案,似乎非常合乎邏輯,但我花了相當長的時間才弄清楚這個問題
如果您正在使用基於 WSDL 的 SOAP 請求,並且您的綁定中有多個操作(具有相同的參數),請確保 <soap:operation> 樣式設定為 rpc,而不是 body!

當您在此處指定 'body' 時,請求中傳輸的將只是函數調用的參數,而 SoapServer->handle() 將使用它找到的第一個具有相同參數組成的函數來處理呼叫。

例如,如果您有 2 個函數
<?php
function One ( string $blah );
function
Two ( string $blah );
?>
當您的 'type' 設定為 'body' 時,使用 SoapClient -> Two ( 'test' ); 進行用戶端呼叫將導致 One ( ) 被呼叫。

只有當您的類型設定為 'rpc' 時,實際要呼叫的方法才會包含在請求中,從而產生預期的行為
prenaud at profideo dot com
12 年前
請注意,當在一個 wsdl 檔案中定義多個服務,並且呼叫其中一個服務時,您可能總是收到第一個服務的回應。

這是一個已知的錯誤。您可以在這裡找到它的描述和一些解決方法:https://bugs.php.net/bug.php?id=49169
none at none dot none
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 錯誤: " . $e->getMessage() . "\n堆疊追蹤:\n" . $e->getTraceAsString());
throw
$e;
}
}

$server = new SoapServer('https://example.com/soap.wsld');
$server->addFunction('testFatal');
$server->handle();
?>
tom at backslashinteractive dot com
16 年前
回應 Blizzke

有時,這個問題可能會被 Apache 區段錯誤以及拋給用戶端的 HTTP 標頭錯誤 SoapFault 所隱藏。

如果您收到這兩者中的任何一個,請嘗試檢查您的 WSDL 檔案的 soap:operation 中是否確定 style="rpc"。

-T
To Top