0

I've spent hours trying to figure this out and nothing I've tried from suggestions on SO to PHP.net have worked. I'm trying to get a SOAP Call to work where I have multiple nested levels of XML and there's attributes on the top level as well as sub levels, and nothing seems to work. Where am I going wrong with my code?

I've tried what seems like everything from SO and PHP.net, but none of the answers seem to go in depth enough or multiple levels of XML, they all seem to assume that you only go one level deep.

I've tried both of the below, in addition to more:

    $params = array("Request"=>array("_"=>array("Credentials"=>array("UserNumberCredentials"=>array("UserNumber"=>$userNumber,"Password"=>$password)),"DeviceInformation"=>array("_"=>"","DeviceType"=>$this->deviceType,"DeviceNumber"=>$this->deviceNumber)),"MessageId"=>$this->messageId));
    $params = array("Request"=>array("_"=>array("Credentials"=>array("_"=>array("UserNumberCredentials"=>array("_"=>array("UserNumber"=>$userNumber,"Password"=>$password)))),"DeviceInformation"=>array("_"=>"","DeviceType"=>$this->deviceType,"DeviceNumber"=>$this->deviceNumber)),"MessageId"=>$this->messageId));

And the expected XML is:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" >
   <soapenv:Header/>
   <soapenv:Body>
      <user:logon>
         <!--Optional:-->
         <Request MessageId="messageId">
            <!--Optional:-->
            <Credentials>
               <!--Optional:-->
               <UserNumberCredentials>
                  <!--Optional:-->
                  <UserNumber>value</UserNumber>
                  <!--Optional:-->
                  <Password>value</Password>
               </UserNumberCredentials>
            </Credentials>
            <!--Optional:-->
            <DeviceInformation DeviceType="deviceType" DeviceNumber="number" />
         </Request>
      </user:logon>
   </soapenv:Body>
</soapenv:Envelope>

I'm passing params into the SOAP call like this:

    $results = $this->client->logon($params);

I've tried multiple ways, and either it returns a validation error, where it says it's missing MessageId attribute on the request tag or when it returns a soap fault saying the device information or credentials are wrong, and I know they're both typed correctly and passed into the wrapping function variables correctly, so they're being passed over the soap call correctly. But because it returns a soap fault, I can't tell the actual formed XML it's passing over.

UPDATE: The below parameters are sort of correct, but both of the DeviceInformation attributes are not being sent I think. I think it's only sending one, so the server is rejecting the call. The DeviceInformation tag itself is empty, but the DeviceNumber and DeviceType attributes are both required in that tag, and I think only one or none are being sent in the call. But it returns a fault, so I'm not able to get the XML to see.

$params = array("Request"=>array("_"=>array("Credentials"=>array("UserNumberCredentials"=>array("UserNumber"=>$userNumber,"Password"=>$password)),"DeviceInformation"=>array("_"=>"","DeviceType"=>$this->deviceType,"DeviceNumber"=>$this->deviceNumber)),"MessageId"=>$this->messageId));
Peter M
  • 3
  • 2
  • Normally, you have to login to a SOAP API by using the SoapHeader and then send your actual form to the appropriate SOAP WS Method.. did you try with Soap-UI and check what are the available requests names? – Michael Tétreault Jun 03 '19 at 19:25
  • I've had an ajax request that worked in JS to the same service, and the XML I pulled from SOAP UI, so I know the service is working, but something in the PHP isn't working, and I'm not sure what. I either get a bad request soap fault, or it's saying it doesn't recognize the Message ID attribute. I had it quasi working once, but it still returned a message that it didn't recognize the device information. – Peter M Jun 03 '19 at 19:42
  • I know that SOAP is a little obscure.. are you trying to login to then send an other request? – Michael Tétreault Jun 03 '19 at 19:44
  • Correct. The login request returns a token, and then that token will be used as authentication for other requests. I think my main issues is the attributes on the tags. I've got an update, but it seems it's not recognizing the device information and credentials, which are being passed in as a function parameter. – Peter M Jun 03 '19 at 19:57
  • Check out my answer, i adapted one of my scripts for this question.. give it a try to see if it help. – Michael Tétreault Jun 03 '19 at 20:05
  • I don't think the answer below entirely answers it. The attributes as posted in the XML above are required, so the DeviceInformation tag has two required attributes, and Request has one. I've managed to get the one for Request working, I tried putting the two attributes into an array, and it didn't work either. – Peter M Jun 03 '19 at 20:17

2 Answers2

0

Here is how i normally login and send my SOAP requests:

<?php
// The form
$params = array(
    "Request"=>array(
        "MessageId"=>$this->messageId,
        "Credentials"=>array(
            "UserNumberCredentials"=>array(
                "UserNumber"=>$userNumber,
                "Password"=>$password
            )
        ),
        "DeviceInformation"=>array(
            "DeviceType"=>$this->deviceType,
            "DeviceNumber"=>$this->deviceNumber
        )
    )
);

// API Configs
$config = array(
    "wsdl" => "https:// ... the wsdl url ... ", // WSDL URL Here
    "namespace" => "http://schemas.xmlsoap.org/soap/envelope/",
    "username" => "", // Username
    "password" => "", // Password
    "soap_options" => array(
        "exceptions" => true,
        "trace" => 1,
        /* If you need a proxy, uncomment
        "proxy_host" => "",
        "proxy_port" => 80,
        */
        "cache_wsdl" => WSDL_CACHE_NONE
    ),
    // For SSL..
    "stream_context" => stream_context_create(array(
        "ssl" => array(
            // set some SSL/TLS specific options
            "verify_peer" => false,
            "verify_peer_name" => false,
            "allow_self_signed" => true
        )
    ))
);

// Initialize soap client object
$client = new SoapClient($config, $config["soap_options"]);

// Credentials
$credentials = array(
    "userName" => $config["username"], 
    "password" => $config["password"]
);
$authvalues = new SoapVar($credentials, SOAP_ENC_OBJECT);

// Headers
$header = new SoapHeader($config["namespace"], "AuthenticationInfo", $authvalues, false);
$client->__setSoapHeaders(array($header));

// Response
$resp = array(
    "status" => "success"
);

// Request
$req = array();
try {
    // SOAP Request 
    $req = $client->logon($params); // Here is the WS Method you want to call.
    $resp["result"] = $req;
} catch(Exception $e) {
    $resp["status"] = "error";
    $resp["details"] = $e;
    $resp["result"] = $req;
    $resp["soap_form"] = $form;
}

echo json_encode($resp);
  • The issue I'm having revolves around attributes on the DeviceInformation tag, not sending the SOAP call itself. I don't think both attributes are being sent, so the server is rejecting it when it receives the call. – Peter M Jun 03 '19 at 20:09
  • I even tried hard coding the values of the variables and got the same rejection error that the DeviceInformation was wrong, and I know I entered the correct values for both attributes, so that's why I'm assuming it's not sending both attributes to the server on the tag. Am I sending the attributes wrong? – Peter M Jun 03 '19 at 20:11
  • Can you please provide your wsdl xml output? – Michael Tétreault Jun 05 '19 at 12:34
0

Apparently the below is how the array was supposed to be formatted to get the attributes in the parameters. I got sample code from someone using the same service, and this was similar to how they formatted it, and it worked. Which is nothing like what I googled, but maybe it will help someone down the road. For the record, my SoapClient is in WSDL mode.

            $params = array(
                "Request"=>array(
                    "MessageId"=>$this->messageId,
                    "Credentials"=>array(
                        "UserNumberCredentials"=>array(
                            "UserNumber"=>$userNumber,
                            "Password"=>$password
                        )
                    ),
                    "DeviceInformation"=>array(
                        "DeviceType"=>$this->deviceType,
                        "DeviceNumber"=>$this->deviceNumber
                    )
                )
            );
Peter M
  • 3
  • 2