SOAP Web service using Spring-WS. Description of Web Services in WSDL language

hats July 23, 2013 at 01:09 pm

Writing SOAP client-server application in PHP

  • PHP
  • Tutorial

Hi all!
It so happened that in Lately I started developing web services. But today the topic is not about me, but about how we can write our own XML Web Service based on the SOAP 1.2 protocol.

I hope that after reading the topic you will be able to:

  • write your own server implementation of a web application;
  • write your own client implementation of a web application;
  • write your own own description web service (WSDL);
  • send the client arrays of the same type of data to the server.
As you might have guessed, all the magic will happen with using PHP and the built-in SoapClient and SoapServer classes. Our rabbit will be a service for sending SMS messages.

1 Problem statement

1.1 Boundaries

At the beginning, I propose to deal with the result that we will achieve at the end of the topic. As announced above, we will be writing a service for sending SMS messages, and more precisely, we will receive messages from different sources via SOAP protocol. After which, we will consider in what form they come to the server. The very process of queuing messages for further sending to the provider, unfortunately, is beyond the scope of of this post for many reasons.

1.2 What data will we change?

Great, we have decided on the boundaries! Next step What needs to be done is to decide what data we will exchange between the server and the client. On this topic, I suggest not to split hairs for too long and immediately answer the main questions for yourself:
  • What minimum data must be sent to the server in order to send an SMS message to a subscriber?
  • What minimum data must be sent from the server to satisfy the client's needs?
Something tells me that for this you need to send the following: In principle, these two characteristics are enough to send, but I immediately imagine the case of an SMS with birthday greetings coming to you at 3 o’clock in the morning, or 4! At this moment, I will be very grateful to everyone for not forgetting about me! Therefore, we will also send to the server and
  • date of sending the SMS message.
The next thing I would like to send to the server is:
  • Message type.
This parameter is not mandatory, but it can be very useful to us if we quickly need to tell the boss how many of our clients we have “delighted” with our news, and also draw some beautiful statistics on this matter.

And yet, I forgot something! If we reflect a little more, it is worth noting that the client can send either one SMS message or a number of them to the server at a time. In other words, one data packet can contain from one to infinity messages.

As a result, we get that to send an SMS message we need the following data:

  • Mobile phone number,
  • SMS message text,
  • time of sending the SMS message to the subscriber,
  • message type.

We have answered the first question, now we need to answer the second question. And perhaps I’ll allow myself to mess around a little. Therefore, from the server we will send only Boolean data, the meaning of which has the following meaning:

  • TRUE – the packet successfully reached the server, passed authentication and queued for sending to the SMS provider
  • FALSE – in all other cases

This concludes the description of the problem statement! And finally, let's get down to the fun part - let's figure out what kind of strange beast this SOAP is!

2 What is SOAP?

In general, initially I did not plan to write anything about what SOAP is and wanted to limit myself to links to the w3.org website with the necessary specifications, as well as links to Wikipedia. But at the very end I decided to write a short note about this protocol.

And I will begin my story with the fact that this data exchange protocol belongs to a subset of protocols based on the so-called RPC (Remote Procedure Call) paradigm, the antipode of which is REST (Representational State Transfer). You can read more about this on Wikipedia; links to articles are at the very end of the topic. From these articles we need to understand the following: “The RPC approach allows you to use a small amount of network resources With big amount methods and complex protocol. With the REST approach, the number of methods and protocol complexity are strictly limited, which means the number of individual resources can be large.” That is, in relation to us, this means that in the case of the RPC approach on the site there will always be one input (link) to the service and what procedure to call to process incoming data we transfer along with the data, while with the REST approach in our The site has many inputs (links), each of which accepts and processes only certain data. If anyone reading knows how to explain the difference in these approaches even more simply, be sure to write in the comments!

The next thing we need to know about SOAP is that this protocol uses the same XML as a transport, which on the one hand is very good, because immediately our arsenal receives the full power of a stack of technologies based on given language markup, namely XML-Schema - a language for describing the structure of an XML document (thanks Wikipedia!), which allows automatic validation of data received by the server from clients.

And so, now we know that SOAP is the protocol used to implement remote call procedures and uses XML as transport! If you read the article on Wikipedia, you can also learn from there that it can be used on top of any protocol application level, and not only in combination with HTTP (unfortunately, in this topic we will only consider SOAP over HTTP). And you know what I like most about all this? If there are no guesses, then I’ll give a hint - SOAP!... Still no guesses?... Are you sure you read the article on Wikipedia?... In general, I won’t torture you further. Therefore, I’ll go straight to the answer: “SOAP (from the English Simple Object Access Protocol - simple protocol access to objects; up to specification 1.2)". The most remarkable thing about this line is in italics! I don’t know what conclusions you drew from all this, but I see the following - since this protocol cannot in any way be called “simple” (and apparently even w3 agrees with this), then from version 1.2 it stopped being decrypted somehow! And it became known as SOAP, just SOAP, period.

Well, okay, please excuse me, I got a little sidetracked. As I wrote earlier, XML is used as transport, and the packets that travel between the client and server are called SOAP envelopes. If you consider the general structure of the envelope, it will seem very familiar to you, because... resembles the structure of an HTML page. It has a main section - Envelop, which includes sections Header And Body, or Fault. IN Body data is transmitted and it is a mandatory section of the envelope, while Header is optional. IN Header authorization or any other data that is not directly related to the input data of the web service procedures may be transmitted. About Fault there is nothing special to tell, except that it comes to the client from the server in case of any errors.

That's it for my review story about SOAP protocol ends (we will look at the envelopes themselves and their structure in more detail when our client and server finally learn to run them into each other) and a new one begins - about the SOAP companion called WSDL (Web Services Description Language). Yes, yes, this is the very thing that scares away most of us from even trying to take and implement our API on this protocol. As a result, we usually reinvent our wheel with JSON as transport. So what is WSDL? WSDL is a language for describing web services and accessing them, based on XML language(c) Wikipedia. If this definition does not make clear to you the entire sacred meaning of this technology, then I will try to describe it in my own words!

WSDL is designed to allow our clients to communicate normally with the server. To do this, the file with the extension “*.wsdl” describes the following information:

  • What namespaces were used?
  • What data schemas were used?
  • What types of messages does the web service expect from clients?
  • Which data belongs to which web service procedures,
  • What procedures does the web service contain?
  • How should the client call the web service procedures,
  • To which address should customer calls be sent?
As seen, this file and there is the entire web service. By specifying the address of the WSDL file in the client, we will know everything about any web service! As a result, we don’t need to know absolutely nothing about where the web service itself is located. All you need to know is the location of its WSDL file! We will soon find out that SOAP is not as scary as Russian proverbs make it out to be.

3 Introduction to XML-Schema

Now we know a lot about what SOAP is, what is inside it, and have an overview of the technology stack that surrounds it. Because, first of all, SOAP is a way of interaction between a client and a server, and language is used as a transport for it XML markup, then in this section We’ll take a little look at how automatic data validation occurs using XML schemas.

The main task of the diagram is to describe the structure of the data that we are going to process. All data in XML schemas is divided into simple(scalar) and complex(structures) types. Simple types include the following types:

  • line,
  • number,
  • boolean value,
  • date of.
Something very simple that has no extensions inside. Their antipode is complex complex types. The simplest example of a complex type that comes to everyone’s mind is objects. For example, a book. The book consists of properties: author, Name, price, ISBN number etc. And these properties, in turn, can be either simple types or complex ones. And the task of the XML schema is to describe this.

I suggest not going far and writing an XML schema for our SMS message! Below is the xml description of the SMS message:

71239876543 Test message 2013-07-20T12:00:00 12
Our complex type diagram will look like this:


This entry reads as follows: We have a variable " message" type " Message"and there is complex type With name " Message", which consists of a sequential set of elements " phone" type string, « text" type string, « date" type dateTime, « type" type decimal. These types are simple and are already defined in the schema description. Congratulations! We just wrote our first XML Schema!

I think that the meaning of the elements " element" And " complexType"Everything has become more or less clear to you, so we won’t focus on them any more and let’s switch straight to the composer element" sequence" When we use the composer element " sequence“We inform you that the elements included in it must always be located in the sequence specified in the diagram, and all of them are mandatory. But don't despair! There are two more composer elements in XML schemas: " choice" And " all" Composer " choice" announces that there must be one of the elements listed in it, and the composer " all» – any combination of the listed elements.

As you remember, in the first section of the topic we agreed that from one to infinity SMS messages can be transmitted in a package. Therefore, I propose to understand how such data is declared in the XML schema. General structure The package might look like this:

71239876543 Test message 1 2013-07-20T12:00:00 12 71239876543 Test message N 2013-07-20T12:00:00 12
The diagram for such a complex type will look like this:


The first block contains the familiar declaration of the complex type “ Message" If you noticed, then in every simple type, included in " Message", new clarifying attributes have been added " minOccurs" And " maxOccurs" As you might guess from the name, the first ( minOccurs) indicates that this sequence must contain at least one element of type “ phone», « text», « date" And " type", while the next one ( maxOccurs) attribute declares to us that there is at most one such element in our sequence. As a result, when we write our own schemas for any data, we are given the widest choice in how to configure them!

The second block of the diagram declares the element " messageList" type " MessageList" It's clear that " MessageList" is a complex type that contains at least one element " message", but the maximum number of such elements is not limited!

4 Write your WSDL

Do you remember that WSDL is our web service? I hope you remember! As we write it, our little web service will run on it. Therefore, I suggest not to mess around.

In general, in order for everything to work correctly for us, we need to transfer a WSDL file with the correct MIME type to the client. To do this, you need to configure your web server accordingly, namely, set the MIME type for files with the “*.wsdl” extension to the following line:

Application/wsdl+xml
But in practice, I usually sent the HTTP header via PHP " text/xml»:

Header("Content-Type: text/xml; charset=utf-8");
and everything worked great!

I want to warn you right away that our simple web service will have a rather impressive description, so don’t be alarmed, because... most of the text is mandatory water and having written it once, you can constantly copy it from one web service to another!

Since WSDL is XML, you need to write about this directly in the very first line. The root element of the file should always be named " definitions»:


Typically, WSDL consists of 4-5 main blocks. The very first block is the definition of a web service or, in other words, the entry point.


It says here that we have a service called - “ SmsService" In principle, all the names in the WSDL file can be changed by you to whatever you want, because they play absolutely no role.

After this we announce that in our web service " SmsService" there is an entry point ("port") called " SmsServicePort" It is to this entry point that all requests from clients to the server will be sent. And indicate in the element “ address» link to the handler file that will accept requests.

Once we have defined the web service and specified the entry point for it, we need to bind supported procedures to it:


To do this, it lists which operations and in what form they will be called. Those. for port " SmsServicePort" a binding is defined under the name " SmsServiceBinding", which has a call type " rpc"and HTTP is used as the transmission protocol. Thus, we indicated here that we will make an RPC call over HTTP. After this we describe which procedures ( operation) are supported in the web service. We will support only one procedure – “ sendSms" Through this procedure our wonderful messages will be sent to the server! After the procedure has been declared, it is necessary to indicate in what form the data will be transmitted. IN in this case it is specified that standard SOAP envelopes will be used.

After that, we need to bind the procedure to messages:


To do this, we specify that our binding is of type " SmsServicePortType" and in the element " portType"with the name of the same type, we indicate the binding of procedures to messages. So, incoming message(from client to server) will be called " sendSmsRequest", and outgoing (from server to client) " sendSmsResponse" Like all names in WSDL, the names of incoming and outgoing messages are arbitrary.

Now we need to describe the messages themselves, i.e. incoming and outgoing:


To do this we add the elements " message" with names " sendSmsRequest" And " sendSmsResponse" respectively. In them we indicate that the input should be an envelope whose structure corresponds to the data type " Request" After which an envelope is returned from the server containing the data type - “ Response».

Now we need to do just a little - add a description of these types to our WSDL file! And how do you think the WSDL describes incoming and outgoing data? I think that you have already understood everything a long time ago and told yourself that using XML schemas! And you will be absolutely right!


You can congratulate us! Our first WSDL has been written! And we are one step closer to achieving our goal.
Next, we'll look at what PHP provides us with for developing our own distributed applications.

5 Our first SOAP server

Earlier I wrote that to create a SOAP server in PHP we will use the built-in SoapServer class. In order for everything further actions happened the same way as mine, you will need to tweak your PHP a little. To be even more precise, you need to make sure that you have the “php-soap” extension installed. It is best to read how to install it on your web server on the official PHP website (see the list of references).

After everything has been installed and configured, we will need to create a file in the root folder of your hosting “ smsservice.php» with the following content:

setClass("SoapSmsGateWay"); //Start the server $server->handle();
I hope there is no need to explain what is above the line with the “ini_set” function. Because there it is determined which HTTP headers we will send from the server to the client and the environment is configured. In the line with “ini_set” we disable caching of the WSDL file so that our changes in it immediately take effect on the client.

Now we come to the server! As you can see, the entire SOAP server takes only three lines! On the first line, we create a new instance of the SoapServer object and pass the address of our WSDL description of the web service to its constructor. Now we know that it will be located in the root of the hosting in a file with the self-explanatory name “ smsservice.wsdl.php" In the second line, we tell the SOAP server which class needs to be pulled in order to process the envelope received from the client and return the envelope with the response. As you might have guessed, it is in this class that our only method will be described sendSms. On the third line we start the server! That's it, our server is ready! With which I congratulate us all!

Now we need to create the WSDL file. To do this, you can either simply copy its contents from the previous section, or take liberties and “template” it a little:

"; ?> /" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http:// schemas.xmlsoap.org/wsdl/http/" name="SmsWsdl" xmlns="http://schemas.xmlsoap.org/wsdl/"> /"> /smsservice.php" />
At this stage, we should be completely satisfied with the resulting server, because We can log the envelopes coming to it and then calmly analyze the incoming data. In order for us to receive anything on the server, we need a client. So let's get to it!

6 SOAP client on the way

First of all, we need to create a file in which we will write the client. As usual, we will create it in the root of the host and call it " client.php", and inside we will write the following:

messageList = new MessageList(); $req->messageList->message = new Message(); $req->messageList->message->phone = "79871234567"; $req->messageList->message->text = "Test message 1"; $req->messageList->message->date = "2013-07-21T15:00:00.26"; $req->messageList->message->type = 15; $client = new SoapClient("http://($_SERVER["HTTP_HOST"])/smsservice.wsdl.php", array("soap_version" => SOAP_1_2)); var_dump($client->sendSms($req));
Let's describe our objects. When we wrote the WSDL, it described three entities for the envelope incoming to the server: Request, MessageList And Message. Accordingly classes Request, MessageList And Message are reflections of these entities in our PHP script.

Once we have defined the objects, we need to create an object ( $req), which we will send to the server. After which come the two most cherished lines for us! Our SOAP client! Believe it or not, this is enough for our server to start receiving messages from the client, as well as for our server to successfully receive and process them! In the first of them, we create an instance of the SoapClient class and pass the address of the location of the WSDL file to its constructor, and in the parameters we explicitly indicate that we will work using the SOAP protocol version 1.2. On the next line we call the method sendSms object $client and immediately display the result in the browser.
Let's run it and see what we finally got!

The following object was returned to me from the server:

Object(stdClass) public "status" => boolean true
And this is great, because... Now we know for sure that our server is working and not only works, but can also return some values ​​to the client!

Now let's look at the log that we prudently keep on the server side! In its first part we see the raw data that arrived on the server:

79871234567 Test message 1 2013-07-21T15:00:00.26 15
This is the envelope. Now you know what it looks like! But it’s unlikely that we’ll be interested in looking at it all the time, so let’s deserialize the object from the log file and see if everything is fine:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1 " (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public "type" => string "15" (length=2)
As you can see, the object was deserialized correctly, for which I want to congratulate us all! Something more interesting awaits us next! Namely, we will send the client to the server not just one SMS message, but a whole pack (to be more precise, three)!

7 Sending complex objects

Let's think about how we can transfer a whole bunch of messages to the server in one packet? Probably the most in a simple way there will be an array organization inside the messageList element! Let's do this:

// create an object to send to the server $req = new Request(); $req->messageList = new MessageList(); $msg1 = new Message(); $msg1->phone = "79871234567"; $msg1->text = "Test message 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->type = 15; $msg2 = new Message(); $msg2->phone = "79871234567"; $msg2->text = "Test message 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->type = 16; $msg3 = new Message(); $msg3->phone = "79871234567"; $msg3->text = "Test message 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->type = 17; $req->messageList->message = $msg1; $req->messageList->message = $msg2; $req->messageList->message = $msg3;
Our logs indicate that the following packet was received from the client:

79871234567 Test message 1 2013-07-21T15:00:00.26 15 79871234567 Test message 2 2014-08-22T16:01:10 16 79871234567 Test message 3 2014-08-22T16:01:10 17
What nonsense, you say? And you will be right in a sense, because... As soon as we learned that an object left the client, it came to our server in absolutely the same form in the form of an envelope. True, SMS messages were not serialized in XML in the way we needed - they had to be wrapped in elements message, not in Struct. Now let's see in what form such an object comes to the method sendSms:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "Struct" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public " type" => string "15" (length=2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length= 37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone " => string "79871234567" (length=11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length= 19) public "type" => string "17" (length=2)
What does this knowledge give us? Only that the path we have chosen is not correct and we have not received an answer to the question - “How can we get on the server correct structure data? But I suggest not to despair and try to convert our array to the type an object:

$req->messageList->message = (object)$req->messageList->message;
In this case, we will receive another envelope:

79871234567 Test message 1 2013-07-21T15:00:00.26 15 79871234567 Test message 2 2014-08-22T16:01:10 16 79871234567 Test message 3 2014-08-22T16:01:10 17
Came into the method sendSms the object has the following structure:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public " type" => string "15" (length=2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length= 37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone " => string "79871234567" (length=11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length= 19) public "type" => string "17" (length=2)
As for me, “the sum does not change from changing the places of the terms” (c). What BOGUS, What Struct– we have not yet achieved our goal! And to achieve it, we need to make sure that instead of these incomprehensible names our native one is displayed message. But the author does not yet know how to achieve this. Therefore, the only thing we can do is get rid of the extra container. In other words, we will now make sure that instead of message became BOGUS! To do this, change the object as follows:

// create an object to send to the server $req = new Request(); $msg1 = new Message(); $msg1->phone = "79871234567"; $msg1->text = "Test message 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->type = 15; $msg2 = new Message(); $msg2->phone = "79871234567"; $msg2->text = "Test message 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->type = 16; $msg3 = new Message(); $msg3->phone = "79871234567"; $msg3->text = "Test message 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->type = 17; $req->messageList = $msg1; $req->messageList = $msg2; $req->messageList = $msg3; $req->messageList = (object)$req->messageList;
Maybe we'll get lucky and get caught up in the scheme correct name? To do this, let's look at the envelope that arrived:

79871234567 Test message 1 2013-07-21T15:00:00.26 15 79871234567 Test message 2 2014-08-22T16:01:10 16 79871234567 Test message 3 2014-08-22T16:01:10 17
Yes, a miracle did not happen! BOGUS– we won’t win! Came to sendSms the object in this case will look like this:

Object(stdClass) public "messageList" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public " text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public "type" => string "15" (length =2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length=37) public "date" => string " 2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone" => string "79871234567" (length= 11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string " 17" (length=2)
As they say – “Almost”! On this (slightly sad) note, I propose to slowly wrap things up and draw some conclusions for ourselves.

8 Conclusion

Finally we got here! Let's figure out what you can do now:
  • you can write the WSDL file necessary for your web service;
  • you can easily write your own client that can communicate with the server via SOAP;
  • you can write your own own server communicating with the outside world via SOAP;
  • you can send arrays of the same type of objects to the server from your client (with some restrictions).
We also made some discoveries during our little research:
  • the native SoapClient class does not correctly serialize data structures of the same type in XML;
  • when serializing an array to XML it creates extra element With name Struct;
  • when serializing an object to XML it creates an extra element called BOGUS;
  • BOGUS less evil than Struct due to the fact that the envelope is more compact (extra namespaces are not added to the XML header of the envelope);
  • Unfortunately, the SoapServer class does not automatically validate the envelope data with our XML schema (perhaps other servers do not do this either).

Binding extension elements are used to specify a specific grammar for incoming (3) and outgoing (4) error messages (5). Operation level (2) and binding level (1) information may also be specified.

The operation binding element contains data for the operation of the same name of the associated port type. However, the operation name in general case is not unique (example: overloading methods / functions - using the same names with different signatures), therefore it may not be enough to uniquely determine the target operation of the port type. In such cases, the target operation is addressed using additional task corresponding wsdl:input and wsdl:output element names using name attribute.

Binding must install only one protocol.

Binding shouldn't contain address information.

Port

A port defines a single endpoint by setting an address to bind to.

  1. <wsdl:definitions .... >
  2. <wsdl:service .... > *
  3. <wsdl:port name = "nmtoken" binding = "qname" > *
  4. <-- extensibility element (1) -->
  5. wsdl:port>
  6. wsdl:service>
  7. wsdl:definitions>

The name attribute specifies unique name among all ports within the WSDL document. The binding attribute of type QName contains a reference to the binding (see).

Extension elements (1) are used to specify the address.

Port should not specify more than one address.

Port should not contain any binding information other than an address.

Service

A service bundles together a set of related ports.

  1. <wsdl:definitions .... >
  2. <wsdl:service name = "nmtoken" > *
  3. <wsdl:port .... /> *
  4. wsdl:service>
  5. wsdl:definitions>

The name attribute specifies a unique name among all services defined within the WSDL document.

Ports within a service are connected as follows:

  • The ports do not communicate with each other (that is, the output of one port is not the input of another).
  • If a service has multiple ports that share general type ports, but use different bindings or have different addresses, such ports are alternative. Each such port implements logically equivalent behavior (within the transport and message format restrictions imposed by the corresponding binding). This allows the client to select a specific port for communication based on various criteria (support transport protocol etc.).
  • By looking at ports, you can determine which port types are supported by the service. Based on this data, the client can determine the ability to interact with a specific service. This is useful if a relationship is implied between operations from different types ports, and to perform a specific task the service must support all required port types.
  1. This is a free, partial, expanded translation of the document Web Services Description Language (WSDL) 1.1 dated March 15, 2001
  2. It is extremely inconvenient to operate with indeclinable terms written in Latin, and they are also unambiguously translated. That's why original name is given only when a new term is introduced, and further in the text the Russian translation is used.

WSDL (Web Services Description Language) version 1.1 was published on March 15, 2001. WSDL is an XML-based format used to describe web services using messages containing information on how to access a specific web service. WSDL we expand, which allows us to describe services (services) and their messages, regardless of what message formats or network protocols are used for transport, however, WSDL 1.1 is most often used along with SOAP 1.1, HTTP GET/POST and MIME. Because the WSDL was developed jointly with SOAP, the same people participated in its development Microsoft, Ariba and IBM. If we consider the document WSDL intuitively, we can say that it allows answer 4 questions:

1) what are you doing? The answer to this question is given in a form suitable for both human perception and machine-perceivable form. Answer for the person in the tags:<name/>, <documentation/>, for car -<message/>, <pointType>

2) what language do you speak? (what types are you using?) Answer in the tag:<types/>

3) how will I communicate with you? (how will the client access the web service?): HTTP or SMTP. The answer lies in<binding/>

4) where can I find you? (where can I find this web service or what is its URL?). The answer is:<service/>

Structure:

Each WSDL document can be broken down into three logical parts:

1. defining data types - determination of the type of sent and received XML service messages

2. abstract operations - list of operations that can be performed with messages

3. service linking - the method in which the message will be delivered

Documentation WSDL can be created manually, but the language is strictly formalized WSDL allows you to automate the writing process WSDL-documents. Many Web service authoring tools contain utilities that automatically create WSDL-files describing ready-made Web services. For example, Web Services Authoring Tool Apache Axis contains a class Java2WSDL, creating WSDL- a file of a Java class or interface that describes a Web service. The IBM WSTK package, which includes Axis, contains the utility java2wsdl, which creates and runs an object from this class. It works from the command line.

WSDL Document Elements

Let's describe the most commonly used WSDL tags:

Tag is the root tag of all WSDL documents. It defines several namespaces:

1)target Name space is the namespace of our web service

2) xmlns – standard WSDL document namespace

3)xmlns: SOAP_ENC – namespace used to describe the SOAP encoding


4) xmlns: impl and intf – the namespace of the implementation and definition of our web service

· Web Service Definition Document

· Document for implementing a web service

For simplicity, as a rule, they use 1 file that contains all the information

Element - provides information about the data that is transferred from one endpoint to another.

To describe an RPC call, you must create an input message and an output message.

Within this element, you can specify method parameters using the element

Element describes and defines the operations or methods supported by a web service

Operations can have input messages as well as error messages.

Element - describes how operations specified in a port type will be transmitted over the network. Because element uses a port type, it must specify a type defined somewhere earlier in the document.

Element - indicates where to find the web service

Element import . Very often the service element is allocated to its wsdl document for reasons of practicality.

In order to allow combining several wsdl documents into one, the import element is used. It allows you to include one wsdl document into another.

Element types allows you to specify the types of data transmitted if they are not standard.

WSDL supports 4 modes of operations:

· one-way or one-way operations. The message is sent to the service endpoint. In this case, the operation is described by only one input message.

· Request-Response – request-response mode. This mode of operation is the most common. In this mode, the operation description contains an input message, an output message, and an optional error message.

· Request-response type operation. In this mode, an endpoint is a client of another endpoint. The operation format is similar to request-response mode, but the output data is listed before the input data.

· Operation notification. This mode is another version of the one-way transmission primitive, in which the endpoint sends the message rather than receiving it. The operation contains only an output message.

Page 2 of 3

Description using WSDL

SOAP works very well if everything is known about the Web service. However, this is not always the case. The means of describing the interface for accessing a Web service is the WSDL language (Web Services Description Language). This standard was jointly developed IBM companies, Microsoft and webMethods. Each of these three companies had their own approach to developing a standard for describing Web services: IBM created NASSL, Microsoft developed SCL, and webMethods came up with WIDL.

The result of their collaboration was version 1.1 of the WSDL language. Regarding the W3C, it should be noted that, as with SOAP, the W3C consortium based on version 1.1 developed WSDL 1.2, which is now a W3C recommendation. The WSDL description of a Web service contains all the information necessary to use the service, including available methods and their parameters. This information is contained in the following five elements:

  • - supported protocols.
  • - Web service messages (request, response).
  • All available methods.
  • - Service URI.
  • - used data types.

All this information is stored in root element WSDL descriptions ,The listing below shows an example of a WSDL ,description of a Web service.

WSDL description of the Web service

Yeah... you can’t figure it out without a glass, but this is one of the simplest(!) WSDL files. Unfortunately, one of the drawbacks of the SOAP extension for PHP 5 is that, unlike other SOAP implementations, it does not automatically generate WSDL descriptions (at least not yet). Surely this flaw will be corrected in future versions of PHP.

By the way!

To automatically generate the WSDL description, you can use alternative implementations of the SOAP protocol in PHP:

Directory Search Using UDDI

Now that we know how to get information about a Web service and how to query it, we need to learn how to find such a service. For this purpose, there is something similar to the Yellow Pages, namely the UBR (Universal Business Registries) registries - Web service directories.

There are several such registries, including those of IBM, Microsoft, NTT-Com and SAP. These registries synchronize their data, so you can use any of them. The current version of the UDDI standard is UDDI 3.0, although most implementations use version 2. The developers of this standard include giant companies such as HP, Intel, Microsoft and Sun.

To interact with UBR there is two types of APIs: Inquiry API and Publish API. Interface Inquiry API (Request) is for requesting services in UBR registries, and the interface Publish API allows developers to register their services. Looks like it's only a matter of time before the contents of the registries become filled with spam :)

By the way!

There are test registries designed to test service registrations before placing them in the "real" registries.

This is what a Web service request looks like:

sortByNameAsc sortByDateDesc %guid%

In the example above, you can see that the UDDI request is encapsulated in a SOAP message, so it looks quite familiar. The response to the request is also a SOAP document, shown below:

Web Services Guided Tour Sample Web services for Guided Tourbook Guided Tour StockQuote Service

Installation

Installing the SOAP extension for PHP5 is quite easy. On Windows, this module is located in the ext subdirectory of the PHP installation directory. To use it, you need to add the following line to the php.ini file: extension=php_soap.dll To work, this module requires that it is included in PHP 5 by default, at least in the Windows version.

  • Tutorial

Hi all!
It so happened that recently I began to develop web services. But today the topic is not about me, but about how we can write our own XML Web Service based on the SOAP 1.2 protocol.

I hope that after reading the topic you will be able to:

  • write your own server implementation of a web application;
  • write your own client implementation of a web application;
  • write your own web service description (WSDL);
  • send the client arrays of the same type of data to the server.
As you might have guessed, all the magic will be done using PHP and the built-in SoapClient and SoapServer classes. Our rabbit will be a service for sending SMS messages.

1 Problem statement

1.1 Boundaries

At the beginning, I propose to deal with the result that we will achieve at the end of the topic. As announced above, we will write a service for sending SMS messages, and more precisely, we will receive messages from different sources via the SOAP protocol. After which, we will consider in what form they come to the server. The process of queuing messages for further sending to the provider, unfortunately, is beyond the scope of this post for many reasons.

1.2 What data will we change?

Great, we have decided on the boundaries! The next step that needs to be taken is to decide what data we will exchange between the server and the client. On this topic, I suggest not to split hairs for too long and immediately answer the main questions for yourself:
  • What minimum data must be sent to the server in order to send an SMS message to a subscriber?
  • What minimum data must be sent from the server to satisfy the client's needs?
Something tells me that for this you need to send the following:
  • mobile phone number and
  • text of the SMS message.
In principle, these two characteristics are enough to send, but I immediately imagine the case of an SMS with birthday greetings coming to you at 3 o’clock in the morning, or 4! At this moment, I will be very grateful to everyone for not forgetting about me! Therefore, we will also send to the server and
  • date of sending the SMS message.
The next thing I would like to send to the server is:
  • Message type.
This parameter is not mandatory, but it can be very useful to us if we quickly need to tell the boss how many of our clients we have “delighted” with our news, and also draw some beautiful statistics on this matter.

And yet, I forgot something! If we reflect a little more, it is worth noting that the client can send either one SMS message or a number of them to the server at a time. In other words, one data packet can contain from one to infinity messages.

As a result, we get that to send an SMS message we need the following data:

  • Mobile phone number,
  • SMS message text,
  • time of sending the SMS message to the subscriber,
  • message type.

We have answered the first question, now we need to answer the second question. And perhaps I’ll allow myself to mess around a little. Therefore, from the server we will send only Boolean data, the meaning of which has the following meaning:

  • TRUE – the packet successfully reached the server, passed authentication and queued for sending to the SMS provider
  • FALSE – in all other cases

This concludes the description of the problem statement! And finally, let's get down to the fun part - let's figure out what kind of strange beast this SOAP is!

2 What is SOAP?

In general, initially I did not plan to write anything about what SOAP is and wanted to limit myself to links to the w3.org website with the necessary specifications, as well as links to Wikipedia. But at the very end I decided to write a short note about this protocol.

And I will begin my story with the fact that this data exchange protocol belongs to a subset of protocols based on the so-called RPC (Remote Procedure Call) paradigm, the antipode of which is REST (Representational State Transfer). You can read more about this on Wikipedia; links to articles are at the very end of the topic. From these articles, we need to understand the following: “The RPC approach allows the use of a small number of network resources with a large number of methods and a complex protocol. With the REST approach, the number of methods and protocol complexity are strictly limited, which means the number of individual resources can be large.” That is, in relation to us, this means that in the case of the RPC approach on the site there will always be one input (link) to the service and what procedure to call to process incoming data we transfer along with the data, while with the REST approach in our The site has many inputs (links), each of which accepts and processes only certain data. If anyone reading knows how to explain the difference in these approaches even more simply, be sure to write in the comments!

The next thing we need to know about SOAP is that this protocol uses the same XML as a transport, which on the one hand is very good, because Our arsenal immediately includes the full power of a stack of technologies based on this markup language, namely XML-Schema - a language for describing the structure of an XML document (thanks Wikipedia!), which allows for automatic validation of data received by the server from clients.

And so, now we know that SOAP is a protocol used to implement remote procedure calls and it uses XML as a transport! If you read the article on Wikipedia, you can also learn from there that it can be used over any application-level protocol, and not just in combination with HTTP (unfortunately, in this topic we will only consider SOAP over HTTP). And you know what I like most about all this? If there are no guesses, then I’ll give a hint - SOAP!... Still no guesses?... Are you sure you read the article on Wikipedia?... In general, I won’t torture you further. Therefore, I’ll go straight to the answer: “SOAP (from the English Simple Object Access Protocol - simple protocol access to objects; up to specification 1.2)". The most remarkable thing about this line is in italics! I don’t know what conclusions you drew from all this, but I see the following - since this protocol cannot in any way be called “simple” (and apparently even w3 agrees with this), then from version 1.2 it stopped being decrypted somehow! And it became known as SOAP, just SOAP, period.

Well, okay, please excuse me, I got a little sidetracked. As I wrote earlier, XML is used as transport, and the packets that travel between the client and server are called SOAP envelopes. If you consider the general structure of the envelope, it will seem very familiar to you, because... resembles the structure of an HTML page. It has a main section - Envelop, which includes sections Header And Body, or Fault. IN Body data is transmitted and it is a mandatory section of the envelope, while Header is optional. IN Header authorization or any other data that is not directly related to the input data of the web service procedures may be transmitted. About Fault there is nothing special to tell, except that it comes to the client from the server in case of any errors.

This is where my review story about the SOAP protocol ends (we will look at the envelopes themselves and their structure in more detail when our client and server finally learn to run them at each other) and a new one begins - about the SOAP companion called WSDL(Web Services Description Language). Yes, yes, this is the very thing that scares most of us away from even trying to implement our API on this protocol. As a result, we usually reinvent our wheel with JSON as transport. So what is WSDL? WSDL is a language for describing web services and accessing them, based on the XML language (c) Wikipedia. If this definition does not make clear to you the entire sacred meaning of this technology, then I will try to describe it in my own words!

WSDL is designed to allow our clients to communicate normally with the server. To do this, the file with the extension “*.wsdl” describes the following information:

  • What namespaces were used?
  • What data schemas were used?
  • What types of messages does the web service expect from clients?
  • Which data belongs to which web service procedures,
  • What procedures does the web service contain?
  • How should the client call the web service procedures,
  • To which address should customer calls be sent?
As you can see, this file is the entire web service. By specifying the address of the WSDL file in the client, we will know everything about any web service! As a result, we don’t need to know absolutely nothing about where the web service itself is located. All you need to know is the location of its WSDL file! We will soon find out that SOAP is not as scary as Russian proverbs make it out to be.

3 Introduction to XML-Schema

Now we know a lot about what SOAP is, what is inside it, and have an overview of the technology stack that surrounds it. Since, first of all, SOAP is a method of interaction between a client and a server, and XML markup language is used as a transport for it, in this section we will understand a little about how automatic data validation occurs using XML schemas.

The main task of the diagram is to describe the structure of the data that we are going to process. All data in XML schemas is divided into simple(scalar) and complex(structures) types. Simple types include the following types:

  • line,
  • number,
  • boolean value,
  • date of.
Something very simple that has no extensions inside. Their antipode is complex complex types. The simplest example of a complex type that comes to everyone’s mind is objects. For example, a book. The book consists of properties: author, Name, price, ISBN number etc. And these properties, in turn, can be either simple types or complex ones. And the task of the XML schema is to describe this.

I suggest not going far and writing an XML schema for our SMS message! Below is the xml description of the SMS message:

71239876543 Test message 2013-07-20T12:00:00 12
Our complex type diagram will look like this:


This entry reads as follows: We have a variable " message" type " Message" and there is a complex type called " Message", which consists of a sequential set of elements " phone" type string, « text" type string, « date" type dateTime, « type" type decimal. These types are simple and are already defined in the schema description. Congratulations! We just wrote our first XML Schema!

I think that the meaning of the elements " element" And " complexType"Everything has become more or less clear to you, so we won’t focus on them any more and let’s switch straight to the composer element" sequence" When we use the composer element " sequence“We inform you that the elements included in it must always be located in the sequence specified in the diagram, and all of them are mandatory. But don't despair! There are two more composer elements in XML schemas: " choice" And " all" Composer " choice" announces that there must be one of the elements listed in it, and the composer " all» – any combination of the listed elements.

As you remember, in the first section of the topic we agreed that from one to infinity SMS messages can be transmitted in a package. Therefore, I propose to understand how such data is declared in the XML schema. The general package structure might look like this:

71239876543 Test message 1 2013-07-20T12:00:00 12 71239876543 Test message N 2013-07-20T12:00:00 12
The diagram for such a complex type will look like this:


The first block contains the familiar declaration of the complex type “ Message" If you noticed, then in each simple type included in " Message", new clarifying attributes have been added " minOccurs" And " maxOccurs" As you might guess from the name, the first ( minOccurs) indicates that this sequence must contain at least one element of type “ phone», « text», « date" And " type", while the next one ( maxOccurs) attribute declares to us that there is at most one such element in our sequence. As a result, when we write our own schemas for any data, we are given the widest choice in how to configure them!

The second block of the diagram declares the element " messageList" type " MessageList" It's clear that " MessageList" is a complex type that contains at least one element " message", but the maximum number of such elements is not limited!

4 Write your WSDL

Do you remember that WSDL is our web service? I hope you remember! As we write it, our little web service will run on it. Therefore, I suggest not to mess around.

In general, in order for everything to work correctly for us, we need to transfer a WSDL file with the correct MIME type to the client. To do this, you need to configure your web server accordingly, namely, set the MIME type for files with the “*.wsdl” extension to the following line:

Application/wsdl+xml
But in practice, I usually sent the HTTP header via PHP " text/xml»:

Header("Content-Type: text/xml; charset=utf-8");
and everything worked great!

I want to warn you right away that our simple web service will have a rather impressive description, so don’t be alarmed, because... Most of the text is obligatory water and, having written it once, you can constantly copy it from one web service to another!

Since WSDL is XML, you need to write about this directly in the very first line. The root element of the file should always be named " definitions»:


Typically, WSDL consists of 4-5 main blocks. The very first block is the definition of a web service or, in other words, the entry point.


It says here that we have a service called - “ SmsService" In principle, all the names in the WSDL file can be changed by you to whatever you want, because they play absolutely no role.

After this we announce that in our web service " SmsService" there is an entry point ("port") called " SmsServicePort" It is to this entry point that all requests from clients to the server will be sent. And indicate in the element “ address» link to the handler file that will accept requests.

Once we have defined the web service and specified the entry point for it, we need to bind supported procedures to it:


To do this, it lists which operations and in what form they will be called. Those. for port " SmsServicePort" a binding is defined under the name " SmsServiceBinding", which has a call type " rpc"and HTTP is used as the transmission protocol. Thus, we indicated here that we will make an RPC call over HTTP. After this we describe which procedures ( operation) are supported in the web service. We will support only one procedure – “ sendSms" Through this procedure our wonderful messages will be sent to the server! After the procedure has been declared, it is necessary to indicate in what form the data will be transmitted. In this case, it is indicated that standard SOAP envelopes will be used.

After that, we need to bind the procedure to messages:


To do this, we specify that our binding is of type " SmsServicePortType" and in the element " portType"with the name of the same type, we indicate the binding of procedures to messages. And so, the incoming message (from client to server) will be called “ sendSmsRequest", and outgoing (from server to client) " sendSmsResponse" Like all names in WSDL, the names of incoming and outgoing messages are arbitrary.

Now we need to describe the messages themselves, i.e. incoming and outgoing:


To do this we add the elements " message" with names " sendSmsRequest" And " sendSmsResponse" respectively. In them we indicate that the input should be an envelope whose structure corresponds to the data type " Request" After which an envelope is returned from the server containing the data type - “ Response».

Now we need to do just a little - add a description of these types to our WSDL file! And how do you think the WSDL describes incoming and outgoing data? I think that you have already understood everything a long time ago and told yourself that using XML schemas! And you will be absolutely right!


You can congratulate us! Our first WSDL has been written! And we are one step closer to achieving our goal.
Next, we'll look at what PHP provides us with for developing our own distributed applications.

5 Our first SOAP server

Earlier I wrote that to create a SOAP server in PHP we will use the built-in SoapServer class. In order for all further actions to happen the same way as for me, you will need to tweak your PHP a little. To be even more precise, you need to make sure that you have the “php-soap” extension installed. It is best to read how to install it on your web server on the official PHP website (see the list of references).

After everything has been installed and configured, we will need to create a file in the root folder of your hosting “ smsservice.php» with the following content:

setClass("SoapSmsGateWay"); //Start the server $server->handle();
I hope there is no need to explain what is above the line with the “ini_set” function. Because there it is determined which HTTP headers we will send from the server to the client and the environment is configured. In the line with “ini_set” we disable caching of the WSDL file so that our changes in it immediately take effect on the client.

Now we come to the server! As you can see, the entire SOAP server takes only three lines! On the first line, we create a new instance of the SoapServer object and pass the address of our WSDL description of the web service to its constructor. Now we know that it will be located in the root of the hosting in a file with the self-explanatory name “ smsservice.wsdl.php" In the second line, we tell the SOAP server which class needs to be pulled in order to process the envelope received from the client and return the envelope with the response. As you might have guessed, it is in this class that our only method will be described sendSms. On the third line we start the server! That's it, our server is ready! With which I congratulate us all!

Now we need to create the WSDL file. To do this, you can either simply copy its contents from the previous section, or take liberties and “template” it a little:

"; ?> /" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http:// schemas.xmlsoap.org/wsdl/http/" name="SmsWsdl" xmlns="http://schemas.xmlsoap.org/wsdl/"> /"> /smsservice.php" />
At this stage, we should be completely satisfied with the resulting server, because We can log the envelopes coming to it and then calmly analyze the incoming data. In order for us to receive anything on the server, we need a client. So let's get to it!

6 SOAP client on the way

First of all, we need to create a file in which we will write the client. As usual, we will create it in the root of the host and call it " client.php", and inside we will write the following:

messageList = new MessageList(); $req->messageList->message = new Message(); $req->messageList->message->phone = "79871234567"; $req->messageList->message->text = "Test message 1"; $req->messageList->message->date = "2013-07-21T15:00:00.26"; $req->messageList->message->type = 15; $client = new SoapClient("http://($_SERVER["HTTP_HOST"])/smsservice.wsdl.php", array("soap_version" => SOAP_1_2)); var_dump($client->sendSms($req));
Let's describe our objects. When we wrote the WSDL, it described three entities for the envelope incoming to the server: Request, MessageList And Message. Accordingly classes Request, MessageList And Message are reflections of these entities in our PHP script.

Once we have defined the objects, we need to create an object ( $req), which we will send to the server. After which come the two most cherished lines for us! Our SOAP client! Believe it or not, this is enough for our server to start receiving messages from the client, as well as for our server to successfully receive and process them! In the first of them, we create an instance of the SoapClient class and pass the address of the location of the WSDL file to its constructor, and in the parameters we explicitly indicate that we will work using the SOAP protocol version 1.2. On the next line we call the method sendSms object $client and immediately display the result in the browser.
Let's run it and see what we finally got!

The following object was returned to me from the server:

Object(stdClass) public "status" => boolean true
And this is great, because... Now we know for sure that our server is working and not only works, but can also return some values ​​to the client!

Now let's look at the log that we prudently keep on the server side! In its first part we see the raw data that arrived on the server:

79871234567 Test message 1 2013-07-21T15:00:00.26 15
This is the envelope. Now you know what it looks like! But it’s unlikely that we’ll be interested in looking at it all the time, so let’s deserialize the object from the log file and see if everything is fine:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1 " (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public "type" => string "15" (length=2)
As you can see, the object was deserialized correctly, for which I want to congratulate us all! Something more interesting awaits us next! Namely, we will send the client to the server not just one SMS message, but a whole pack (to be more precise, three)!

7 Sending complex objects

Let's think about how we can transfer a whole bunch of messages to the server in one packet? Probably the easiest way would be to organize an array inside the messageList element! Let's do this:

// create an object to send to the server $req = new Request(); $req->messageList = new MessageList(); $msg1 = new Message(); $msg1->phone = "79871234567"; $msg1->text = "Test message 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->type = 15; $msg2 = new Message(); $msg2->phone = "79871234567"; $msg2->text = "Test message 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->type = 16; $msg3 = new Message(); $msg3->phone = "79871234567"; $msg3->text = "Test message 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->type = 17; $req->messageList->message = $msg1; $req->messageList->message = $msg2; $req->messageList->message = $msg3;
Our logs indicate that the following packet was received from the client:

79871234567 Test message 1 2013-07-21T15:00:00.26 15 79871234567 Test message 2 2014-08-22T16:01:10 16 79871234567 Test message 3 2014-08-22T16:01:10 17
What nonsense, you say? And you will be right in a sense, because... As soon as we learned that an object left the client, it came to our server in absolutely the same form in the form of an envelope. True, SMS messages were not serialized in XML in the way we needed - they had to be wrapped in elements message, not in Struct. Now let's see in what form such an object comes to the method sendSms:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "Struct" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public " type" => string "15" (length=2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length= 37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone " => string "79871234567" (length=11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length= 19) public "type" => string "17" (length=2)
What does this knowledge give us? Only that the path we have chosen is not correct and we have not received an answer to the question - “How can we get the correct data structure on the server?” But I suggest not to despair and try to convert our array to the type an object:

$req->messageList->message = (object)$req->messageList->message;
In this case, we will receive another envelope:

79871234567 Test message 1 2013-07-21T15:00:00.26 15 79871234567 Test message 2 2014-08-22T16:01:10 16 79871234567 Test message 3 2014-08-22T16:01:10 17
Came into the method sendSms the object has the following structure:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public " type" => string "15" (length=2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length= 37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone " => string "79871234567" (length=11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length= 19) public "type" => string "17" (length=2)
As for me, “the sum does not change from changing the places of the terms” (c). What BOGUS, What Struct– we have not yet achieved our goal! And to achieve it, we need to make sure that instead of these incomprehensible names our native one is displayed message. But the author does not yet know how to achieve this. Therefore, the only thing we can do is get rid of the extra container. In other words, we will now make sure that instead of message became BOGUS! To do this, change the object as follows:

// create an object to send to the server $req = new Request(); $msg1 = new Message(); $msg1->phone = "79871234567"; $msg1->text = "Test message 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->type = 15; $msg2 = new Message(); $msg2->phone = "79871234567"; $msg2->text = "Test message 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->type = 16; $msg3 = new Message(); $msg3->phone = "79871234567"; $msg3->text = "Test message 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->type = 17; $req->messageList = $msg1; $req->messageList = $msg2; $req->messageList = $msg3; $req->messageList = (object)$req->messageList;
What if we get lucky and the correct name comes up from the diagram? To do this, let's look at the envelope that arrived:

79871234567 Test message 1 2013-07-21T15:00:00.26 15 79871234567 Test message 2 2014-08-22T16:01:10 16 79871234567 Test message 3 2014-08-22T16:01:10 17
Yes, a miracle did not happen! BOGUS– we won’t win! Came to sendSms the object in this case will look like this:

Object(stdClass) public "messageList" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public " text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public "type" => string "15" (length =2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length=37) public "date" => string " 2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone" => string "79871234567" (length= 11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string " 17" (length=2)
As they say – “Almost”! On this (slightly sad) note, I propose to slowly wrap things up and draw some conclusions for ourselves.

8 Conclusion

Finally we got here! Let's figure out what you can do now:
  • you can write the WSDL file necessary for your web service;
  • you can easily write your own client that can communicate with the server via SOAP;
  • you can write your own server that communicates with the outside world via SOAP;
  • you can send arrays of the same type of objects to the server from your client (with some restrictions).
We also made some discoveries during our little research:
  • the native SoapClient class does not correctly serialize data structures of the same type in XML;
  • when serializing an array to XML it creates an extra element called Struct;
  • when serializing an object to XML it creates an extra element called BOGUS;
  • BOGUS less evil than Struct due to the fact that the envelope is more compact (extra namespaces are not added to the XML header of the envelope);
  • Unfortunately, the SoapServer class does not automatically validate the envelope data with our XML schema (perhaps other servers do not do this either).