Skip to content

Commit e58af7c

Browse files
lxShaDoWxlnielsdos
authored andcommittedOct 23, 2023
ext/soap: Add support for clark notation for namespaces in class map
Closes GH-12411.
1 parent fa218ea commit e58af7c

12 files changed

+466
-93
lines changed
 

‎NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ SimpleXML:
3131
foreach). (nielsdos)
3232
. Fixed bug #55098 (SimpleXML iteration produces infinite loop). (nielsdos)
3333

34+
SOAP:
35+
. Add support for clark notation for namespaces in class map. (lxShaDoWxl)
36+
3437
Standard:
3538
. Implement GH-12188 (Indication for the int size in phpinfo()). (timwolla)
3639
. Partly fix GH-12143 (Incorrect round() result for 0.49999999999999994).

‎UPGRADING

+6
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ PHP 8.4 UPGRADE NOTES
7979
. Added constant DOMNode::DOCUMENT_POSITION_CONTAINED_BY.
8080
. Added constant DOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC.
8181

82+
- SOAP:
83+
. Added support for clark notation for namespaces in class map.
84+
It is now possible to specify entries in a class map with clark notation
85+
to resolve a type with a specific namespace to a specific class.
86+
For example: '{http://example.com}foo' => 'FooClass'.
87+
8288
- XSL:
8389
. It is now possible to use parameters that contain both single and double
8490
quotes.

‎ext/soap/php_encoding.c

+106-88
Large diffs are not rendered by default.

‎ext/soap/php_encoding.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ struct _encodeType {
181181
int type;
182182
char *type_str;
183183
char *ns;
184+
zend_string *clark_notation;
184185
sdlTypePtr sdl_type;
185186
soapMappingPtr map;
186187
};
@@ -214,7 +215,7 @@ encodePtr get_conversion(int encode);
214215
void delete_encoder(zval *zv);
215216
void delete_encoder_persistent(zval *zv);
216217

217-
extern const encode defaultEncoding[];
218+
extern encode defaultEncoding[];
218219
extern int numDefaultEncodings;
219220

220221
#endif

‎ext/soap/php_schema.c

+12
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ static encodePtr create_encoder(sdlPtr sdl, sdlTypePtr cur_type, const xmlChar *
6464
if (enc->details.type_str) {
6565
efree(enc->details.type_str);
6666
}
67+
if (enc->details.clark_notation) {
68+
zend_string_release_ex(enc->details.clark_notation, 0);
69+
}
6770
} else {
6871
enc_ptr = NULL;
6972
enc = emalloc(sizeof(encode));
@@ -73,6 +76,9 @@ static encodePtr create_encoder(sdlPtr sdl, sdlTypePtr cur_type, const xmlChar *
7376
enc->details.ns = estrdup((char*)ns);
7477
enc->details.type_str = estrdup((char*)type);
7578
enc->details.sdl_type = cur_type;
79+
if (enc->details.ns != NULL){
80+
enc->details.clark_notation = zend_strpprintf(0, "{%s}%s", enc->details.ns, enc->details.type_str);
81+
}
7682
enc->to_xml = sdl_guess_convert_xml;
7783
enc->to_zval = sdl_guess_convert_zval;
7884

@@ -335,6 +341,9 @@ static int schema_simpleType(sdlPtr sdl, xmlAttrPtr tns, xmlNodePtr simpleType,
335341
memset(cur_type->encode, 0, sizeof(encode));
336342
cur_type->encode->details.ns = estrdup(newType->namens);
337343
cur_type->encode->details.type_str = estrdup(newType->name);
344+
if (cur_type->encode->details.ns) {
345+
cur_type->encode->details.clark_notation = zend_strpprintf(0, "{%s}%s", cur_type->encode->details.ns, cur_type->encode->details.type_str);
346+
}
338347
cur_type->encode->details.sdl_type = ptr;
339348
cur_type->encode->to_xml = sdl_guess_convert_xml;
340349
cur_type->encode->to_zval = sdl_guess_convert_zval;
@@ -1390,6 +1399,9 @@ static int schema_complexType(sdlPtr sdl, xmlAttrPtr tns, xmlNodePtr compType, s
13901399
memset(cur_type->encode, 0, sizeof(encode));
13911400
cur_type->encode->details.ns = estrdup(newType->namens);
13921401
cur_type->encode->details.type_str = estrdup(newType->name);
1402+
if (cur_type->encode->details.ns) {
1403+
cur_type->encode->details.clark_notation = zend_strpprintf(0, "{%s}%s", cur_type->encode->details.ns, cur_type->encode->details.type_str);
1404+
}
13931405
cur_type->encode->details.sdl_type = ptr;
13941406
cur_type->encode->to_xml = sdl_guess_convert_xml;
13951407
cur_type->encode->to_zval = sdl_guess_convert_zval;

‎ext/soap/php_sdl.c

+7
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ encodePtr get_encoder(sdlPtr sdl, const char *ns, const char *type)
153153
new_enc->details.ns = estrndup(ns, ns_len);
154154
new_enc->details.type_str = estrdup(new_enc->details.type_str);
155155
}
156+
if (new_enc->details.clark_notation) {
157+
zend_string_addref(new_enc->details.clark_notation);
158+
}
156159
if (sdl->encoders == NULL) {
157160
sdl->encoders = pemalloc(sizeof(HashTable), sdl->is_persistent);
158161
zend_hash_init(sdl->encoders, 0, NULL, delete_encoder, sdl->is_persistent);
@@ -1419,6 +1422,9 @@ static void sdl_deserialize_encoder(encodePtr enc, sdlTypePtr *types, char **in)
14191422
WSDL_CACHE_GET_INT(enc->details.type, in);
14201423
enc->details.type_str = sdl_deserialize_string(in);
14211424
enc->details.ns = sdl_deserialize_string(in);
1425+
if (enc->details.ns) {
1426+
enc->details.clark_notation = zend_strpprintf(0, "{%s}%s", enc->details.ns, enc->details.type_str);
1427+
}
14221428
WSDL_CACHE_GET_INT(i, in);
14231429
enc->details.sdl_type = types[i];
14241430
enc->to_xml = sdl_guess_convert_xml;
@@ -2845,6 +2851,7 @@ static encodePtr make_persistent_sdl_encoder(encodePtr enc, HashTable *ptr_map,
28452851
}
28462852
if (penc->details.ns) {
28472853
penc->details.ns = strdup(penc->details.ns);
2854+
penc->details.clark_notation = zend_string_dup(penc->details.clark_notation, 1);
28482855
}
28492856

28502857
if (penc->details.sdl_type) {

‎ext/soap/soap.c

+14-4
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ static HashTable defEnc, defEncIndex, defEncNs;
293293
static void php_soap_prepare_globals(void)
294294
{
295295
int i;
296-
const encode* enc;
296+
encode* enc;
297297

298298
zend_hash_init(&defEnc, 0, NULL, NULL, 1);
299299
zend_hash_init(&defEncIndex, 0, NULL, NULL, 1);
@@ -306,9 +306,12 @@ static void php_soap_prepare_globals(void)
306306
/* If has a ns and a str_type then index it */
307307
if (defaultEncoding[i].details.type_str) {
308308
if (defaultEncoding[i].details.ns != NULL) {
309-
char *ns_type;
310-
spprintf(&ns_type, 0, "%s:%s", defaultEncoding[i].details.ns, defaultEncoding[i].details.type_str);
311-
zend_hash_str_add_ptr(&defEnc, ns_type, strlen(ns_type), (void*)enc);
309+
char *ns_type, *clark_notation;
310+
size_t clark_notation_len = spprintf(&clark_notation, 0, "{%s}%s", enc->details.ns, enc->details.type_str);
311+
enc->details.clark_notation = zend_string_init(clark_notation, clark_notation_len, true);
312+
size_t ns_type_len = spprintf(&ns_type, 0, "%s:%s", enc->details.ns, enc->details.type_str);
313+
zend_hash_str_add_ptr(&defEnc, ns_type, ns_type_len, (void*)enc);
314+
efree(clark_notation);
312315
efree(ns_type);
313316
} else {
314317
zend_hash_str_add_ptr(&defEnc, defaultEncoding[i].details.type_str, strlen(defaultEncoding[i].details.type_str), (void*)enc);
@@ -348,6 +351,13 @@ static void php_soap_init_globals(zend_soap_globals *soap_globals)
348351

349352
PHP_MSHUTDOWN_FUNCTION(soap)
350353
{
354+
int i = 0;
355+
do {
356+
if (defaultEncoding[i].details.clark_notation) {
357+
zend_string_release_ex(defaultEncoding[i].details.clark_notation, 1);
358+
}
359+
i++;
360+
} while (defaultEncoding[i].details.type != END_KNOWN_TYPES);
351361
zend_error_cb = old_error_handler;
352362
zend_hash_destroy(&SOAP_GLOBAL(defEnc));
353363
zend_hash_destroy(&SOAP_GLOBAL(defEncIndex));

‎ext/soap/tests/classmap005.phpt

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--TEST--
2+
SOAP Classmap 5: SoapClient support for classmap with namespace
3+
--EXTENSIONS--
4+
soap
5+
--INI--
6+
soap.wsdl_cache_enabled=0
7+
--FILE--
8+
<?php
9+
class TestSoapClient extends SoapClient{
10+
function __doRequest($request, $location, $action, $version, $one_way = 0): ?string {
11+
return <<<EOF
12+
<?xml version="1.0" encoding="UTF-8"?>
13+
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>
14+
<ns1:dotest2Response><res xsi:type="ns1:book">
15+
<a xsi:type="xsd:string">Blaat</a>
16+
<b xsi:type="xsd:string">aap</b>
17+
</res>
18+
</ns1:dotest2Response></SOAP-ENV:Body></SOAP-ENV:Envelope>
19+
EOF;
20+
}
21+
}
22+
23+
class bookNs {
24+
public $a="a";
25+
public $b="c";
26+
}
27+
28+
class book {
29+
public $a="a";
30+
public $b="c";
31+
}
32+
33+
$options=Array(
34+
'actor' =>'http://schema.nothing.com',
35+
'classmap' => array('book'=>'book', '{http://schemas.nothing.com}book'=>'bookNs')
36+
);
37+
38+
$client = new TestSoapClient(__DIR__."/classmap.wsdl",$options);
39+
$ret = $client->dotest2("???");
40+
var_dump($ret);
41+
echo "ok\n";
42+
?>
43+
--EXPECT--
44+
object(bookNs)#2 (2) {
45+
["a"]=>
46+
string(5) "Blaat"
47+
["b"]=>
48+
string(3) "aap"
49+
}
50+
ok

‎ext/soap/tests/classmap006.phpt

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
--TEST--
2+
SOAP Classmap 6: encoding of inherited objects with namespace
3+
--EXTENSIONS--
4+
soap
5+
--INI--
6+
soap.wsdl_cache_enabled=0
7+
--FILE--
8+
<?php
9+
class A {
10+
public $x;
11+
function __construct($a){
12+
$this->x = $a;
13+
}
14+
}
15+
class Attest {
16+
public $x;
17+
function __construct($a){
18+
$this->x = $a;
19+
}
20+
}
21+
class B extends A {
22+
public $y;
23+
function __construct($a){
24+
parent::__construct($a);
25+
$this->y = $a + 1;
26+
}
27+
}
28+
29+
function f($input){
30+
return new B(5);
31+
}
32+
33+
class LocalSoapClient extends SoapClient {
34+
private $server;
35+
36+
function __construct($wsdl, $options) {
37+
parent::__construct($wsdl, $options);
38+
$this->server = new SoapServer($wsdl, $options);
39+
$this->server->addFunction("f");
40+
}
41+
42+
function __doRequest($request, $location, $action, $version, $one_way = 0): ?string {
43+
ob_start();
44+
$this->server->handle($request);
45+
$response = ob_get_contents();
46+
ob_end_clean();
47+
return $response;
48+
}
49+
}
50+
51+
$client = new LocalSoapClient(__DIR__."/classmap006.wsdl",
52+
array('classmap'=>array('A'=>'A','{urn:abt}At'=>'Attest','B'=>'B')));
53+
print_r($client->f(new Attest('test')));
54+
?>
55+
--EXPECT--
56+
B Object
57+
(
58+
[x] => 5
59+
[y] => 6
60+
)

‎ext/soap/tests/classmap006.wsdl

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
3+
<!-- WSDL file generated by Zend Studio. -->
4+
5+
<definitions name="ab" targetNamespace="urn:ab" xmlns:typens="urn:ab" xmlns:typenst="urn:abt" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/">
6+
<types>
7+
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:ab">
8+
<xsd:complexType name="A">
9+
<xsd:sequence>
10+
<xsd:element name="x" type="xsd:anyType"/>
11+
</xsd:sequence>
12+
</xsd:complexType>
13+
<xsd:complexType name="B">
14+
<xsd:complexContent>
15+
<xsd:extension base="typens:A">
16+
<xsd:sequence>
17+
<xsd:element name="y" type="xsd:anyType"/>
18+
</xsd:sequence>
19+
</xsd:extension>
20+
</xsd:complexContent>
21+
</xsd:complexType>
22+
</xsd:schema>
23+
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:abt">
24+
<xsd:complexType name="At">
25+
<xsd:sequence>
26+
<xsd:element name="x" type="xsd:anyType"/>
27+
</xsd:sequence>
28+
</xsd:complexType>
29+
<xsd:complexType name="Bt">
30+
<xsd:complexContent>
31+
<xsd:extension base="typens:A">
32+
<xsd:sequence>
33+
<xsd:element name="y" type="xsd:anyType"/>
34+
</xsd:sequence>
35+
</xsd:extension>
36+
</xsd:complexContent>
37+
</xsd:complexType>
38+
</xsd:schema>
39+
40+
</types>
41+
<message name="f">
42+
<part name="fInput" type="xsd:anyType"/>
43+
</message>
44+
<message name="fResponse">
45+
<part name="fReturn" type="typens:A"/>
46+
</message>
47+
<portType name="abServerPortType">
48+
<operation name="f">
49+
<input message="typens:f"/>
50+
<output message="typens:fResponse"/>
51+
</operation>
52+
</portType>
53+
<binding name="abServerBinding" type="typens:abServerPortType">
54+
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
55+
<operation name="f">
56+
<soap:operation soapAction="urn:abServerAction"/>
57+
<input>
58+
<soap:body namespace="urn:ab" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
59+
</input>
60+
<output>
61+
<soap:body namespace="urn:ab" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
62+
</output>
63+
</operation>
64+
</binding>
65+
<service name="abService">
66+
<port name="abServerPort" binding="typens:abServerBinding">
67+
<soap:address location="http://localhost/abServer.php"/>
68+
</port>
69+
</service>
70+
</definitions>

‎ext/soap/tests/classmap007.phpt

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
--TEST--
2+
SOAP Classmap 7: encoding of inherited objects with namespace and cache wsdl
3+
--EXTENSIONS--
4+
soap
5+
--INI--
6+
soap.wsdl_cache_enabled=1
7+
--FILE--
8+
<?php
9+
class A {
10+
public $x;
11+
function __construct($a){
12+
$this->x = $a;
13+
}
14+
}
15+
class Attest {
16+
public $x;
17+
function __construct($a){
18+
$this->x = $a;
19+
}
20+
}
21+
class B extends A {
22+
public $y;
23+
function __construct($a){
24+
parent::__construct($a);
25+
$this->y = $a + 1;
26+
}
27+
}
28+
29+
function f($input){
30+
return new B(5);
31+
}
32+
33+
class LocalSoapClient extends SoapClient {
34+
private $server;
35+
36+
function __construct($wsdl, $options) {
37+
parent::__construct($wsdl, $options);
38+
$this->server = new SoapServer($wsdl, $options);
39+
$this->server->addFunction("f");
40+
}
41+
42+
function __doRequest($request, $location, $action, $version, $one_way = 0): ?string {
43+
ob_start();
44+
$this->server->handle($request);
45+
$response = ob_get_contents();
46+
ob_end_clean();
47+
return $response;
48+
}
49+
}
50+
51+
$client = new LocalSoapClient(__DIR__."/classmap007.wsdl",
52+
array('classmap'=>array('A'=>'A','{urn:abt}At'=>'Attest','B'=>'B')));
53+
print_r($client->f(new Attest('test')));
54+
print_r($client->f(new Attest('test')));
55+
?>
56+
--EXPECT--
57+
B Object
58+
(
59+
[x] => 5
60+
[y] => 6
61+
)
62+
B Object
63+
(
64+
[x] => 5
65+
[y] => 6
66+
)

0 commit comments

Comments
 (0)
Please sign in to comment.