From ff6b1ae76dbd2380328ec814c966c449976963b4 Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Sat, 7 Sep 2024 23:18:26 +0200
Subject: [PATCH] Implement request #47317: SoapServer::__getLastResponse()
Convenient for debugging.
---
ext/soap/php_soap.h | 3 +
ext/soap/soap.c | 24 +++++++
ext/soap/soap.stub.php | 2 +
ext/soap/soap_arginfo.h | 7 +-
.../tests/SoapServer/__getLastResponse.phpt | 65 +++++++++++++++++++
5 files changed, 100 insertions(+), 1 deletion(-)
create mode 100644 ext/soap/tests/SoapServer/__getLastResponse.phpt
diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h
index 715af76faf5fb..a78734aa7f17a 100644
--- a/ext/soap/php_soap.h
+++ b/ext/soap/php_soap.h
@@ -98,6 +98,9 @@ struct _soapService {
int features;
int send_errors;
struct _soapHeader **soap_headers_ptr;
+
+ bool trace;
+ zend_string *last_response_body;
};
#define SOAP_CLASS 1
diff --git a/ext/soap/soap.c b/ext/soap/soap.c
index 401fbde9d82a9..5f0a661ecba51 100644
--- a/ext/soap/soap.c
+++ b/ext/soap/soap.c
@@ -983,6 +983,11 @@ PHP_METHOD(SoapServer, __construct)
}
}
+ if ((tmp = zend_hash_find(ht, ZSTR_KNOWN(ZEND_STR_TRACE))) != NULL &&
+ (Z_TYPE_P(tmp) == IS_TRUE ||
+ (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 1))) {
+ service->trace = true;
+ }
} else if (!wsdl) {
php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
}
@@ -1644,6 +1649,12 @@ PHP_METHOD(SoapServer, handle)
sapi_add_header(cont_len, strlen(cont_len), 1);
}
php_write(buf, size);
+ if (service->trace) {
+ if (service->last_response_body) {
+ zend_string_release_ex(service->last_response_body, false);
+ }
+ service->last_response_body = zend_string_init((const char *) buf, size, false);
+ }
xmlFree(buf);
} else {
sapi_add_header("HTTP/1.1 202 Accepted", sizeof("HTTP/1.1 202 Accepted")-1, 1);
@@ -1752,6 +1763,16 @@ PHP_METHOD(SoapServer, addSoapHeader)
}
/* }}} */
+PHP_METHOD(SoapServer, __getLastResponse)
+{
+ soapServicePtr service;
+ ZEND_PARSE_PARAMETERS_NONE();
+ FETCH_THIS_SERVICE_NO_BAILOUT(service);
+ if (service->last_response_body) {
+ RETURN_STR_COPY(service->last_response_body);
+ }
+}
+
static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader *hdr) /* {{{ */
{
int soap_version;
@@ -4533,6 +4554,9 @@ static void delete_service(soapServicePtr service) /* {{{ */
zend_hash_destroy(service->class_map);
FREE_HASHTABLE(service->class_map);
}
+ if (service->last_response_body) {
+ zend_string_release_ex(service->last_response_body, false);
+ }
zval_ptr_dtor(&service->soap_object);
efree(service);
}
diff --git a/ext/soap/soap.stub.php b/ext/soap/soap.stub.php
index a387c3a2d7555..82f884e24b308 100644
--- a/ext/soap/soap.stub.php
+++ b/ext/soap/soap.stub.php
@@ -527,6 +527,8 @@ public function addFunction($functions): void {}
/** @tentative-return-type */
public function handle(?string $request = null): void {}
+
+ public function __getLastResponse(): ?string {}
}
class SoapClient
diff --git a/ext/soap/soap_arginfo.h b/ext/soap/soap_arginfo.h
index 4f6709094dd33..ca0d2d9644e84 100644
--- a/ext/soap/soap_arginfo.h
+++ b/ext/soap/soap_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 66221c42416635403ee6d49c12884e94073b67f2 */
+ * Stub hash: 7712aba90b16090fbe7c124c1e3f26b2cc3e2ab2 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_use_soap_error_handler, 0, 0, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 0, "true")
@@ -84,6 +84,9 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapServer_handl
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, request, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SoapServer___getLastResponse, 0, 0, IS_STRING, 1)
+ZEND_END_ARG_INFO()
+
#define arginfo_class_SoapClient___construct arginfo_class_SoapServer___construct
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapClient___call, 0, 2, IS_MIXED, 0)
@@ -152,6 +155,7 @@ ZEND_METHOD(SoapServer, setObject);
ZEND_METHOD(SoapServer, getFunctions);
ZEND_METHOD(SoapServer, addFunction);
ZEND_METHOD(SoapServer, handle);
+ZEND_METHOD(SoapServer, __getLastResponse);
ZEND_METHOD(SoapClient, __construct);
ZEND_METHOD(SoapClient, __call);
ZEND_METHOD(SoapClient, __soapCall);
@@ -204,6 +208,7 @@ static const zend_function_entry class_SoapServer_methods[] = {
ZEND_ME(SoapServer, getFunctions, arginfo_class_SoapServer_getFunctions, ZEND_ACC_PUBLIC)
ZEND_ME(SoapServer, addFunction, arginfo_class_SoapServer_addFunction, ZEND_ACC_PUBLIC)
ZEND_ME(SoapServer, handle, arginfo_class_SoapServer_handle, ZEND_ACC_PUBLIC)
+ ZEND_ME(SoapServer, __getLastResponse, arginfo_class_SoapServer___getLastResponse, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
diff --git a/ext/soap/tests/SoapServer/__getLastResponse.phpt b/ext/soap/tests/SoapServer/__getLastResponse.phpt
new file mode 100644
index 0000000000000..83c20d3c3a49c
--- /dev/null
+++ b/ext/soap/tests/SoapServer/__getLastResponse.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Request #47317 (SoapServer::__getLastResponse)
+--EXTENSIONS--
+soap
+--INI--
+soap.wsdl_cache_enabled=0
+--FILE--
+server = new SoapServer($wsdl, $options);
+ $this->server->addFunction("f");
+ }
+
+ function __doRequest($request, $location, $action, $version, $one_way = 0): string {
+ ob_start();
+ $this->server->handle($request);
+ $response = ob_get_contents();
+ ob_end_clean();
+ return $response;
+ }
+}
+
+$client = new LocalSoapClient(__DIR__."/../classmap003.wsdl", ["trace" => false]);
+$client->f();
+var_dump($client->__getLastResponse());
+var_dump($client->server->__getLastResponse());
+var_dump($client->__getLastResponse() === $client->server->__getLastResponse());
+
+echo "---\n";
+
+$client = new LocalSoapClient(__DIR__."/../classmap003.wsdl", ["trace" => true]);
+var_dump($client->__getLastResponse());
+var_dump($client->server->__getLastResponse());
+var_dump($client->__getLastResponse() === $client->server->__getLastResponse());
+
+echo "---\n";
+
+$client->f();
+echo $client->__getLastResponse(), "\n";
+echo $client->server->__getLastResponse(), "\n";
+var_dump($client->__getLastResponse() === $client->server->__getLastResponse());
+?>
+--EXPECT--
+NULL
+NULL
+bool(true)
+---
+NULL
+NULL
+bool(true)
+---
+
+
+
+
+
+
+bool(true)