Skip to content

Commit

Permalink
ext/soap: Add support for clark notation for namespaces in class map
Browse files Browse the repository at this point in the history
Closes GH-12411.
  • Loading branch information
lxShaDoWxl authored and nielsdos committed Oct 23, 2023
1 parent fa218ea commit e58af7c
Show file tree
Hide file tree
Showing 12 changed files with 466 additions and 93 deletions.
3 changes: 3 additions & 0 deletions NEWS
Expand Up @@ -31,6 +31,9 @@ SimpleXML:
foreach). (nielsdos)
. Fixed bug #55098 (SimpleXML iteration produces infinite loop). (nielsdos)

SOAP:
. Add support for clark notation for namespaces in class map. (lxShaDoWxl)

Standard:
. Implement GH-12188 (Indication for the int size in phpinfo()). (timwolla)
. Partly fix GH-12143 (Incorrect round() result for 0.49999999999999994).
Expand Down
6 changes: 6 additions & 0 deletions UPGRADING
Expand Up @@ -79,6 +79,12 @@ PHP 8.4 UPGRADE NOTES
. Added constant DOMNode::DOCUMENT_POSITION_CONTAINED_BY.
. Added constant DOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC.

- SOAP:
. Added support for clark notation for namespaces in class map.
It is now possible to specify entries in a class map with clark notation
to resolve a type with a specific namespace to a specific class.
For example: '{http://example.com}foo' => 'FooClass'.

- XSL:
. It is now possible to use parameters that contain both single and double
quotes.
Expand Down
194 changes: 106 additions & 88 deletions ext/soap/php_encoding.c

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion ext/soap/php_encoding.h
Expand Up @@ -181,6 +181,7 @@ struct _encodeType {
int type;
char *type_str;
char *ns;
zend_string *clark_notation;
sdlTypePtr sdl_type;
soapMappingPtr map;
};
Expand Down Expand Up @@ -214,7 +215,7 @@ encodePtr get_conversion(int encode);
void delete_encoder(zval *zv);
void delete_encoder_persistent(zval *zv);

extern const encode defaultEncoding[];
extern encode defaultEncoding[];
extern int numDefaultEncodings;

#endif
12 changes: 12 additions & 0 deletions ext/soap/php_schema.c
Expand Up @@ -64,6 +64,9 @@ static encodePtr create_encoder(sdlPtr sdl, sdlTypePtr cur_type, const xmlChar *
if (enc->details.type_str) {
efree(enc->details.type_str);
}
if (enc->details.clark_notation) {
zend_string_release_ex(enc->details.clark_notation, 0);
}
} else {
enc_ptr = NULL;
enc = emalloc(sizeof(encode));
Expand All @@ -73,6 +76,9 @@ static encodePtr create_encoder(sdlPtr sdl, sdlTypePtr cur_type, const xmlChar *
enc->details.ns = estrdup((char*)ns);
enc->details.type_str = estrdup((char*)type);
enc->details.sdl_type = cur_type;
if (enc->details.ns != NULL){
enc->details.clark_notation = zend_strpprintf(0, "{%s}%s", enc->details.ns, enc->details.type_str);
}
enc->to_xml = sdl_guess_convert_xml;
enc->to_zval = sdl_guess_convert_zval;

Expand Down Expand Up @@ -335,6 +341,9 @@ static int schema_simpleType(sdlPtr sdl, xmlAttrPtr tns, xmlNodePtr simpleType,
memset(cur_type->encode, 0, sizeof(encode));
cur_type->encode->details.ns = estrdup(newType->namens);
cur_type->encode->details.type_str = estrdup(newType->name);
if (cur_type->encode->details.ns) {
cur_type->encode->details.clark_notation = zend_strpprintf(0, "{%s}%s", cur_type->encode->details.ns, cur_type->encode->details.type_str);
}
cur_type->encode->details.sdl_type = ptr;
cur_type->encode->to_xml = sdl_guess_convert_xml;
cur_type->encode->to_zval = sdl_guess_convert_zval;
Expand Down Expand Up @@ -1390,6 +1399,9 @@ static int schema_complexType(sdlPtr sdl, xmlAttrPtr tns, xmlNodePtr compType, s
memset(cur_type->encode, 0, sizeof(encode));
cur_type->encode->details.ns = estrdup(newType->namens);
cur_type->encode->details.type_str = estrdup(newType->name);
if (cur_type->encode->details.ns) {
cur_type->encode->details.clark_notation = zend_strpprintf(0, "{%s}%s", cur_type->encode->details.ns, cur_type->encode->details.type_str);
}
cur_type->encode->details.sdl_type = ptr;
cur_type->encode->to_xml = sdl_guess_convert_xml;
cur_type->encode->to_zval = sdl_guess_convert_zval;
Expand Down
7 changes: 7 additions & 0 deletions ext/soap/php_sdl.c
Expand Up @@ -153,6 +153,9 @@ encodePtr get_encoder(sdlPtr sdl, const char *ns, const char *type)
new_enc->details.ns = estrndup(ns, ns_len);
new_enc->details.type_str = estrdup(new_enc->details.type_str);
}
if (new_enc->details.clark_notation) {
zend_string_addref(new_enc->details.clark_notation);
}
if (sdl->encoders == NULL) {
sdl->encoders = pemalloc(sizeof(HashTable), sdl->is_persistent);
zend_hash_init(sdl->encoders, 0, NULL, delete_encoder, sdl->is_persistent);
Expand Down Expand Up @@ -1419,6 +1422,9 @@ static void sdl_deserialize_encoder(encodePtr enc, sdlTypePtr *types, char **in)
WSDL_CACHE_GET_INT(enc->details.type, in);
enc->details.type_str = sdl_deserialize_string(in);
enc->details.ns = sdl_deserialize_string(in);
if (enc->details.ns) {
enc->details.clark_notation = zend_strpprintf(0, "{%s}%s", enc->details.ns, enc->details.type_str);
}
WSDL_CACHE_GET_INT(i, in);
enc->details.sdl_type = types[i];
enc->to_xml = sdl_guess_convert_xml;
Expand Down Expand Up @@ -2845,6 +2851,7 @@ static encodePtr make_persistent_sdl_encoder(encodePtr enc, HashTable *ptr_map,
}
if (penc->details.ns) {
penc->details.ns = strdup(penc->details.ns);
penc->details.clark_notation = zend_string_dup(penc->details.clark_notation, 1);
}

if (penc->details.sdl_type) {
Expand Down
18 changes: 14 additions & 4 deletions ext/soap/soap.c
Expand Up @@ -293,7 +293,7 @@ static HashTable defEnc, defEncIndex, defEncNs;
static void php_soap_prepare_globals(void)
{
int i;
const encode* enc;
encode* enc;

zend_hash_init(&defEnc, 0, NULL, NULL, 1);
zend_hash_init(&defEncIndex, 0, NULL, NULL, 1);
Expand All @@ -306,9 +306,12 @@ static void php_soap_prepare_globals(void)
/* If has a ns and a str_type then index it */
if (defaultEncoding[i].details.type_str) {
if (defaultEncoding[i].details.ns != NULL) {
char *ns_type;
spprintf(&ns_type, 0, "%s:%s", defaultEncoding[i].details.ns, defaultEncoding[i].details.type_str);
zend_hash_str_add_ptr(&defEnc, ns_type, strlen(ns_type), (void*)enc);
char *ns_type, *clark_notation;
size_t clark_notation_len = spprintf(&clark_notation, 0, "{%s}%s", enc->details.ns, enc->details.type_str);
enc->details.clark_notation = zend_string_init(clark_notation, clark_notation_len, true);
size_t ns_type_len = spprintf(&ns_type, 0, "%s:%s", enc->details.ns, enc->details.type_str);
zend_hash_str_add_ptr(&defEnc, ns_type, ns_type_len, (void*)enc);
efree(clark_notation);
efree(ns_type);
} else {
zend_hash_str_add_ptr(&defEnc, defaultEncoding[i].details.type_str, strlen(defaultEncoding[i].details.type_str), (void*)enc);
Expand Down Expand Up @@ -348,6 +351,13 @@ static void php_soap_init_globals(zend_soap_globals *soap_globals)

PHP_MSHUTDOWN_FUNCTION(soap)
{
int i = 0;
do {
if (defaultEncoding[i].details.clark_notation) {
zend_string_release_ex(defaultEncoding[i].details.clark_notation, 1);
}
i++;
} while (defaultEncoding[i].details.type != END_KNOWN_TYPES);
zend_error_cb = old_error_handler;
zend_hash_destroy(&SOAP_GLOBAL(defEnc));
zend_hash_destroy(&SOAP_GLOBAL(defEncIndex));
Expand Down
50 changes: 50 additions & 0 deletions ext/soap/tests/classmap005.phpt
@@ -0,0 +1,50 @@
--TEST--
SOAP Classmap 5: SoapClient support for classmap with namespace
--EXTENSIONS--
soap
--INI--
soap.wsdl_cache_enabled=0
--FILE--
<?php
class TestSoapClient extends SoapClient{
function __doRequest($request, $location, $action, $version, $one_way = 0): ?string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<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>
<ns1:dotest2Response><res xsi:type="ns1:book">
<a xsi:type="xsd:string">Blaat</a>
<b xsi:type="xsd:string">aap</b>
</res>
</ns1:dotest2Response></SOAP-ENV:Body></SOAP-ENV:Envelope>
EOF;
}
}

class bookNs {
public $a="a";
public $b="c";
}

class book {
public $a="a";
public $b="c";
}

$options=Array(
'actor' =>'http://schema.nothing.com',
'classmap' => array('book'=>'book', '{http://schemas.nothing.com}book'=>'bookNs')
);

$client = new TestSoapClient(__DIR__."/classmap.wsdl",$options);
$ret = $client->dotest2("???");
var_dump($ret);
echo "ok\n";
?>
--EXPECT--
object(bookNs)#2 (2) {
["a"]=>
string(5) "Blaat"
["b"]=>
string(3) "aap"
}
ok
60 changes: 60 additions & 0 deletions ext/soap/tests/classmap006.phpt
@@ -0,0 +1,60 @@
--TEST--
SOAP Classmap 6: encoding of inherited objects with namespace
--EXTENSIONS--
soap
--INI--
soap.wsdl_cache_enabled=0
--FILE--
<?php
class A {
public $x;
function __construct($a){
$this->x = $a;
}
}
class Attest {
public $x;
function __construct($a){
$this->x = $a;
}
}
class B extends A {
public $y;
function __construct($a){
parent::__construct($a);
$this->y = $a + 1;
}
}

function f($input){
return new B(5);
}

class LocalSoapClient extends SoapClient {
private $server;

function __construct($wsdl, $options) {
parent::__construct($wsdl, $options);
$this->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__."/classmap006.wsdl",
array('classmap'=>array('A'=>'A','{urn:abt}At'=>'Attest','B'=>'B')));
print_r($client->f(new Attest('test')));
?>
--EXPECT--
B Object
(
[x] => 5
[y] => 6
)
70 changes: 70 additions & 0 deletions ext/soap/tests/classmap006.wsdl
@@ -0,0 +1,70 @@
<?xml version='1.0' encoding='UTF-8'?>

<!-- WSDL file generated by Zend Studio. -->

<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/">
<types>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:ab">
<xsd:complexType name="A">
<xsd:sequence>
<xsd:element name="x" type="xsd:anyType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="B">
<xsd:complexContent>
<xsd:extension base="typens:A">
<xsd:sequence>
<xsd:element name="y" type="xsd:anyType"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:abt">
<xsd:complexType name="At">
<xsd:sequence>
<xsd:element name="x" type="xsd:anyType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Bt">
<xsd:complexContent>
<xsd:extension base="typens:A">
<xsd:sequence>
<xsd:element name="y" type="xsd:anyType"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>

</types>
<message name="f">
<part name="fInput" type="xsd:anyType"/>
</message>
<message name="fResponse">
<part name="fReturn" type="typens:A"/>
</message>
<portType name="abServerPortType">
<operation name="f">
<input message="typens:f"/>
<output message="typens:fResponse"/>
</operation>
</portType>
<binding name="abServerBinding" type="typens:abServerPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="f">
<soap:operation soapAction="urn:abServerAction"/>
<input>
<soap:body namespace="urn:ab" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body namespace="urn:ab" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="abService">
<port name="abServerPort" binding="typens:abServerBinding">
<soap:address location="http://localhost/abServer.php"/>
</port>
</service>
</definitions>
66 changes: 66 additions & 0 deletions ext/soap/tests/classmap007.phpt
@@ -0,0 +1,66 @@
--TEST--
SOAP Classmap 7: encoding of inherited objects with namespace and cache wsdl
--EXTENSIONS--
soap
--INI--
soap.wsdl_cache_enabled=1
--FILE--
<?php
class A {
public $x;
function __construct($a){
$this->x = $a;
}
}
class Attest {
public $x;
function __construct($a){
$this->x = $a;
}
}
class B extends A {
public $y;
function __construct($a){
parent::__construct($a);
$this->y = $a + 1;
}
}

function f($input){
return new B(5);
}

class LocalSoapClient extends SoapClient {
private $server;

function __construct($wsdl, $options) {
parent::__construct($wsdl, $options);
$this->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__."/classmap007.wsdl",
array('classmap'=>array('A'=>'A','{urn:abt}At'=>'Attest','B'=>'B')));
print_r($client->f(new Attest('test')));
print_r($client->f(new Attest('test')));
?>
--EXPECT--
B Object
(
[x] => 5
[y] => 6
)
B Object
(
[x] => 5
[y] => 6
)

0 comments on commit e58af7c

Please sign in to comment.