Link to home
Start Free TrialLog in
Avatar of Scott Fell
Scott FellFlag for United States of America

asked on

PHP SOAP Call

For this soap xml, I have a class that works below.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <getMoreBeer xmlns="http://www.uri.com/someapi">
	    <strParam1>string</strParam1>
    </getMoreBeer>
  </soap:Body>
</soap:Envelope>

Open in new window


class Beer
{
    public $strUserId = "username";
    public $strPassword = "pass";
    public $params = array();
    
 public function getMoreBeer($strParam1 = "some_brand")
    {
    
        $this->params["strParam1"]=$strParam1;

        $result = self::send('getMoreBeer');

        if(isset($result->getMoreBeer->clsStuff)){
            return $result->getMoreBeer->clsStuff;
        }else{
            return ;
        }
    }
    
  public function logindetails()
    {
        $this->params["strUserId"]=$this->strUserId;
        $this->params["strPassword"]=$this->strPassword;
    }
  public function send($action)
    {
        $this->logindetails();
        $client = new SoapClient('https://www.uri.com/someapi?wsdl');

        return $client->{$action}( $this->params );
    }
}

Open in new window


The question is what will the function look like that needs to be added to the class to target  multi level soap xml  as sample below.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <getBeerBrands xmlns="http://www.uri.com/someapi">
      <objQueryStuff>
        <strParam1>string</strParam1>
        <strParam2>string</strParam2>
        <intParam3>int</intParam3>
        <objStores>
          <strParam4>string</strParam4>
        </objStores>
      </objQueryStuff>
    </getBeerBrands>
  </soap:Body>
</soap:Envelope>

Open in new window

Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

I'll see if I can give you a PHP example in a moment, but just a suggestion -- if at all possible, get rid of SOAP and move to a RESTful interface.  The internet is littered with the rotting husks of failed SOAP project.  In contrast, I've never seen anyone who could not immediately understand and use a RESTful API.
Avatar of Scott Fell

ASKER

I would, but I am consuming a 3rd party API and have no control.
See if this might make sense.  Dealing with SOAP namespaces is not exactly PHP's strong suit.  I find it's easier to just mung the data so you can use a path of less resistance.  Please post back if you have questions about what's going on here.
http://iconoun.com/demo/temp_padas.php
<?php // demo/temp_padas.php

/**
 * See http://www.experts-exchange.com/Programming/Languages/Scripting/PHP/Q_28645118.html
 */
error_reporting(E_ALL);
echo '<pre>';

$xml = <<<EOD
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <getBeerBrands xmlns="http://www.uri.com/someapi">
      <objQueryStuff>
        <strParam1>string</strParam1>
        <strParam2>string</strParam2>
        <intParam3>int</intParam3>
        <objStores>
          <strParam4>string</strParam4>
        </objStores>
      </objQueryStuff>
    </getBeerBrands>
  </soap:Body>
</soap:Envelope>
EOD;


// LOAD THE XML STRING
$obj = simplexml_load_string(mungXML($xml));

// ACTIVATE THIS TO SHOW THE ENTIRE OBJECT MADE FROM THE MUNG XML
// var_dump($obj);

// USE AN ITERATOR TO FIND DATA INSIDE THE OBJECT
foreach ($obj->soap_Body as $b)
{
    var_dump($b);
}

// USE DIRECT ADDRESSING TO FIND DATA INSIDE THE OBJECT
$d = $obj->soap_Body->getBeerBrands->objQueryStuff->objStores;
var_dump($d);



// FUNCTION TO MUNG THE XML SO WE DO NOT HAVE TO DEAL WITH NAMESPACE
function mungXML($xml)
{
    $obj = SimpleXML_Load_String($xml);
    if ($obj === FALSE) return $xml;

    // GET NAMESPACES, IF ANY
    $nss = $obj->getNamespaces(TRUE);
    if (empty($nss)) return $xml;

    // CHANGE ns: INTO ns_
    $nsm = array_keys($nss);
    foreach ($nsm as $key)
    {
        // A REGULAR EXPRESSION TO MUNG THE XML
        $rgx
        = '#'               // REGEX DELIMITER
        . '('               // GROUP PATTERN 1
        . '\<'              // LOCATE A LEFT WICKET
        . '/?'              // MAYBE FOLLOWED BY A SLASH
        . preg_quote($key)  // THE NAMESPACE
        . ')'               // END GROUP PATTERN
        . '('               // GROUP PATTERN 2
        . ':{1}'            // A COLON (EXACTLY ONE)
        . ')'               // END GROUP PATTERN
        . '#'               // REGEX DELIMITER
        ;
        // INSERT THE UNDERSCORE INTO THE TAG NAME
        $rep
        = '$1'          // BACKREFERENCE TO GROUP 1
        . '_'           // LITERAL UNDERSCORE IN PLACE OF GROUP 2
        ;
        // PERFORM THE REPLACEMENT
        $xml =  preg_replace($rgx, $rep, $xml);
    }
    return $xml;
}

Open in new window

It was all going nicely until there was nesting.

Would it be easier to use cURL?  Convert the xml to a $variable and submit via cURL.  That's what I used to do for Classic ASP where everything was done by hand.

<?php
  $soap_request  = "<?xml version=\"1.0\"?>\n";
  $soap_request .= "<soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">\n";
  $soap_request .= "  <soap:Body xmlns:m=\"http://www.example.org/stock\">\n";
  $soap_request .= "    <m:GetStockPrice>\n";
  $soap_request .= "      <m:StockName>IBM</m:StockName>\n";
  $soap_request .= "    </m:GetStockPrice>\n";
  $soap_request .= "  </soap:Body>\n";
  $soap_request .= "</soap:Envelope>";
 
  $header = array(
    "Content-type: text/xml;charset=\"utf-8\"",
    "Accept: text/xml",
    "Cache-Control: no-cache",
    "Pragma: no-cache",
    "SOAPAction: \"run\"",
    "Content-length: ".strlen($soap_request),
  );
 
  $soap_do = curl_init();
  curl_setopt($soap_do, CURLOPT_URL, "http://localhost/php-soap-curl/soap-server.php" );
  curl_setopt($soap_do, CURLOPT_CONNECTTIMEOUT, 10);
  curl_setopt($soap_do, CURLOPT_TIMEOUT,        10);
  curl_setopt($soap_do, CURLOPT_RETURNTRANSFER, true );
  curl_setopt($soap_do, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($soap_do, CURLOPT_SSL_VERIFYHOST, false);
  curl_setopt($soap_do, CURLOPT_POST,           true );
  curl_setopt($soap_do, CURLOPT_POSTFIELDS,     $soap_request);
  curl_setopt($soap_do, CURLOPT_HTTPHEADER,     $header);
 
  if(curl_exec($soap_do) === false) {
    $err = 'Curl error: ' . curl_error($soap_do);
    curl_close($soap_do);
    print $err;
  } else {
    curl_close($soap_do);
    print 'Operation completed without any errors';
  }

Open in new window

http://eureka.ykyuen.info/2011/05/05/php-send-a-soap-request-by-curl/
Maybe I'm missing something. I thought you wanted to consume the SOAP output.

Is there API documentation available?
ASKER CERTIFIED SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks Ray, I will give it a try
Sorry for the delay in accepting.  Ray is always a great resource.
Thanks for the points, Scott!  All the best, ~Ray