Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / productivity / SharePoint

PHP Web Service WSDL Generator / SOAP Server (Document/Literal)

4.80/5 (11 votes)
7 Feb 2013CPOL6 min read 203.4K   6.2K  
Generates the required WSDL file and SOAP server for receiving data from InfoPath (Document/Literal format).

Image 1

Introduction 

It all started because I had developed a PHP/MySQL application that worked in isolation. Then a requirement to submit data from an InfoPath form arose. 

In all my searching on the internet, I couldn't for the life of me find anyone who had documented the process of developing a web service in PHP that could talk to InfoPath - everyone seems to use ASP or C#. I tried using NuSOAP, however the documentation was pretty light on, and I could only really get it to work with RPC encoding. The problem is that InfoPath requires WSDL XML in Document/Literal.... and my knowledge of namespaces and schemas was terrible!

Enter this project... 

Background

This is very basic, and really only covers the Request/Response methods of WSDL. It assumes you already know how to code in PHP and create forms in InfoPath.

Note: Ensure that the PHP_SOAP extension is active in your PHP installation. 

Using the code

This is designed to be very easy to implement and very manageable for upgrades. There are two files that are of interest:

  • wsdl.php
  • soap-service.php

wsdl.php is the script that will generate the WSDL XML for you. This is the file that you aim your SOAP client (InfoPath in this example) towards. soap-service.php is the SOAP server. It can be called whatever you want, provided it is linked correctly in the wsdl.php function declaration.

Step 1

Edit wsdl.php and replace the area below the comments. What we are doing here is naming our Web Service, and defining what functions we want available for the Web Service. Our function is a simple survey to ask a user their name, their favourite colour, and their favourite number. The SOAP Server will save these results to a plain text file. We are calling this function ChooseColour:

PHP
$serviceName = "My Example Web Service Access Point";

$functions[] = array(
"funcName" => "ChooseColour",
    "doc" => "Send a favourite colour and number to a text file.",
    "inputParams" => array(array("name" => "Name", "type" => "string"),
		       array("name" => "FavColour", "type" => "string"),
                           array("name" => "FavNumber", "type" => "int")),
"outputParams" => array(array("name" => "Success", "type" => "boolean")),
"soapAddress" => "http://localhost/soap-service.php"
    );

Hopefully it's pretty obvious, however:

  • serviceName: The name of the Web Service - can be anything provided it is A-Z, 0-9 or spaces.
  • $functions array:
    • funcName: Function name as seen by the SOAP client, and function to run in PHP SOAP server.
    • doc: Documentation about the function, as seen by the SOAP client.
    • inputParams: Array of each input parameter for the function. Each parameter is specified by an array with keys "name" and "type". Type should be one of the W3 XML types. If you have/require no input parameters then don't add this key to your array.
    • outputParams: As per above, except this deals with returned results parameters.
    • soapAddress: This is the SOAP Server that will contain your PHP code for your functions.

There can be as many functions declared in this array as required. All functions are declared in the same manner.

That is all you need to do. You now have a functional WSDL generator!

Step 2:

Now! Let's test it out to make sure it's all working... Place the wsdl.php file on your web server, and point your browser to it. You should see the page listing the name of your Web Service that you declared, and a list of all your functions that you declared. At the bottom in the grey box is the raw XML WSDL output that the SOAP client will see. An example of this output is shown at the top of this article. 

Speaking of SOAP clients: For them to get the XML WSDL output, you need to append "?WSDL" (without the quotes) to the end of the URL, otherwise they will get the page you just saw. Below is what they will receive if you append "?WSDL":

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

<wsdl:definitions 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:s="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.darkerwhite.com/" 
    xmlns:tns="http://www.darkerwhite.com/" 
    name="MyExampleWebServiceAccessPoint" 
>

<wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://www.darkerwhite.com/">
        <s:element name="ChooseColourRequest">
            <s:complexType><s:sequence>
                <s:element minOccurs="1" maxOccurs="1" name="Name" type="s:string" />
                <s:element minOccurs="1" maxOccurs="1" name="FavColour" type="s:string" />
                <s:element minOccurs="1" maxOccurs="1" name="FavNumber" type="s:int" />
            </s:sequence></s:complexType>
        </s:element>
        <s:element name="ChooseColourResponse">
            <s:complexType><s:sequence>
                <s:element minOccurs="1" maxOccurs="1" name="Success" type="s:boolean" />
            </s:sequence></s:complexType>
        </s:element>
    </s:schema>
</wsdl:types>

<wsdl:message name="ChooseColourRequest">
    <wsdl:part name="parameters" element="tns:ChooseColourRequest" />
</wsdl:message>
<wsdl:message name="ChooseColourResponse">
    <wsdl:part name="parameters" element="tns:ChooseColourResponse" />
</wsdl:message>

<wsdl:portType name="ChooseColourPortType">
    <wsdl:operation name="ChooseColour">
        <wsdl:input message="tns:ChooseColourRequest" />
        <wsdl:output message="tns:ChooseColourResponse" />
    </wsdl:operation>
</wsdl:portType>

<wsdl:binding name="ChooseColourBinding" type="tns:ChooseColourPortType">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="ChooseColour">
        <soap:operation soapAction="http://localhost/dwss-service.php#ChooseColour" style="document" />
        <wsdl:input><soap:body use="literal" /></wsdl:input>
        <wsdl:output><soap:body use="literal" /></wsdl:output>
        <wsdl:documentation>Send a favourite colour and number to a text file.</wsdl:documentation>
    </wsdl:operation>
</wsdl:binding>

<wsdl:service name="MyExampleWebServiceAccessPoint">
    <wsdl:port name="ChooseColourPort" binding="tns:ChooseColourBinding">
        <soap:address location="http://localhost/dwss-service.php" />
    </wsdl:port>
</wsdl:service>

</wsdl:definitions>

So, let's test it out in a SOAP client (InfoPath Designer). Fire up InfoPath Designer and create a Data Connection to it. Create a Blank Form, then click on the Data tab in the ribbon, then Data Connections. Then click Add, then Create a new connection to submit data and press Next. Then select To a Web Service and press Next. Now enter the URL to your wsdl.php file... something along the lines of http://localhost/wsdl.php. Add "?WSDL" to the end of it to get the raw XML output (http://localhost/wsdl.php?WSDL). InfoPath will add that for you anyway if you forget. Press Next to access the Web Service!

If everything worked, you should now see a list of your functions that you declared. Selecting a function and pressing next will then give you access to a list of all of your input parameters and their data types. You can now select each of these parameters and choose a data field from your form that will bind to this.

Image 2

Step 3

OK, so we know our connection is available - let's build the form to test it.

From the Home ribbon, drag three TextBoxes (from the Controls section) on to your blank form. Then, drag a button onto your form. Right click on the third textbox, and click TextBox Properties. Select Whole Number (Integer) from the Data Type box. Select the Data Connection following the steps as per in Step 2, except now you can assign the data source fields to the fields you just created. Select the "tns:Name" parameter, then select the radio button "Field or Group". Then press the button to the right of the text box that looks like a series of nodes on a tree. Choose field1 from myFields.

Now select "tns:FavColour" and choose field2 for this.

Finally select "tns:FavNumber" and choose field3 - this is the field we specified as an integer. You will get a validation error upon submitting the form if you have a data type mismatch between the form's fields and the data connection's fields.

Now press Next, and ensure "Set as the default submit connection" is ticked, and press Finish. Right click on the button, and click Button Properties. Click the Action box, and select Submit, then press OK. Now activate Full Trust on the form to allow this to run on the local machine: File -> Form Options -> Security and Trust -> Full Trust.

Finished! Feel free to pretty it up if you want. 

Image 3

Step 4

Now edit our soap-service.php file to implement our ChooseColour() function that we want to call to create our survey results file: 

PHP
<?php
ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache
$server = new SoapServer("http://localhost/wsdl.php?WSDL"); // WSDL file for function definitions
$server->addFunction("ChooseColour");	// Same func name as in our WSDL XML, and below
$server->handle();  

function ChooseColour($formdata) {
    $attempt = false; // File writing attempt successful or not
    $formdata = get_object_vars($formdata); // Pull parameters from SOAP connection
    
    // Sort out the parameters and grab their data
    $myname = $formdata['Name']; 
    $mycolour = $formdata['FavColour'];
    $mynumber = $formdata['FavNumber'];
    
    $str =  "Name: " . $myname . ", ";
    $str .= "Colour: " . $mycolour . ", ";
    $str .= "Number: " . $mynumber . "\r\n";
    
    $filename = "./formdata.txt";
    if (($fp = fopen($filename, "a")) == false) return array('Success' => false);
    if (fwrite($fp, $str)) {
    	$attempt = true;
    }
    fclose($fp);     

    return array('Success' => $attempt);
}
?>

The parameters are automatically sorted from the XML by the SoapServer class' handle function! All we need to do is remember what the name of the parameters were. Easy!

And there you have it! You can now run your InfoPath form and communicate with your PHP projects!

Step 5

Go back in to InfoPath Designer, and on the Home ribbon, press Preview. This will launch the form. Now enter your name in the first field, your favourite colour in the second field, and your favourite number in the last. Finally press Submit. The form will then close. Now navigate to the location of your http://localhost/ folder, and there should be a formdata.txt file there with the information you just entered!

Hopefully I helped someone, as I nearly went postal trying to get this to work. The specific combination of technologies I needed to use hadn't been widely used/documented on the internet, so this is my contribution. Thanks for reading and good luck!

History 

  • Version 1.0.1:
  • Source files converted to UTF-8 encoding, and addition of line below as suggested by W. Kleinschmit (thanks!): 

    PHP
    header("Content-Type: application/soap+xml; charset=utf-8"); 
  • Version 1.0.0:
  • Initial article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)