PHP and SOAP integration - php

I connected to a SOAP server from a client and am trying to send form information back.
The connection works, but I have no idea how to send data back. I have received documentation ( -> http://s000.tinyupload.com/?file_id=89258359616332514672) and am stuck at the function AddApplication
This is the PHP code I've written so far. There is no form integration yet, only dummy data.
<?
$client = new SoapClient(
'https://wstest.hrweb.be/TvBastards/TvBastards/Job.svc?singleWsdl',
array(
'soap_version' => SOAP_1_1
)
);
$params = array(
'username' => 'XXX',
'password' => 'XXX',
'environmentKey' => 'XXX',
);
//Open session
try{
$token = $client->OpenSession($params);
}catch(SoapFault $ex){
echo "<pre>";
print_r($ex->detail->ExceptionDetail);
echo "</pre>";
}
//Add Application
try{
$resp = $client->AddApplication($params, ___THE_XML_SHOULD_BE_HERE___); // I have no idea how I can implement a XML file over here, and make this part work
}catch(SoapFault $ex){
echo "<pre>";
print_r($ex->detail->ExceptionDetail);
echo "</pre>";
}
//Close session
try{
$app = $client->CloseSession($token);
}catch(SoapFault $ex){
echo "<pre>";
print_r($ex);
echo "</pre>";
}`
The error I receive now is the following:
End element 'Body' from namespace 'http://schemas.xmlsoap.org/soap/envelope/' expected. Found element 'param1' from namespace ''. Line 2, position 156.
Which is understandable as I don't provide any XML.
I receive my token so the OpenSession works perfectly. As said, I'm completely stuck at the AddApplication function. This is my first encounter with a SOAP service, so every possible bit of explanation is highly appreciated.

Fixed it, and hopefully it can help out some others. I'll try and put it into steps.
define('SIM_LOGIN', 'LOGIN NAME HERE');
define('SIM_PASSWORD', 'LOGIN PASSWORD HERE');
define('ENV_KEY', 'ENVIRONMENT KEY HERE');
/*** login parameters ***/
$params = array(
'username' => SIM_LOGIN,
'password' => SIM_PASSWORD,
'environmentKey' => ENV_KEY,
);
/*** Set up client ***/
$client = new SoapClient(
__SOAP URL HERE__,
array(
'soap_version' => SOAP_1_1
)
);
After setting up the parameters and connecting to the client, we can start calling functions within the SOAP service. Every SOAP service will be different, so function names and parameters can be different. In below example I need to open a session to retrieve a token. This token is used in all the other functions, so this function is necessary. If something fails I call the "abort()" function.
try{
$token = $client->OpenSession($params);
}catch(SoapFault $ex){
abort();
}
If the token is received I call upon the function AddApplication. This expects the token parameter and an "object" (which is basically an STDClass).
I create an stdClass with all my data:
/*** Create stdClass with requested data ***/
$std = new stdClass();
$std->Firstname = $firstname;
$std->Lastname = $lastname;
$std->Birthdate = $birthdate;
$std->Phone = $phone;
$std->Email = $email;
Be sure to check camelcasing of names or capitals, as this makes all the difference.
Now we call upon the AddApplication function with parameters "token(string)" and "application(object)".
/*** AddApplication ***/
try{
$result = $client->AddApplication(array("token" => $token, "application" => $std));
}catch(SoapFault $ex){
abort();
}
If all goes well the data is stored on the external server and you receive a "success" message. It's possible that you receive a "fail" even without going into the SoapFault. Be sure to log both "$result" and "$ex", as a SOAP service can return a "Fail" but the try-catch sees this as a well formed result.
Last thing to do is close the session (and destroy the token)
/*** CloseSession ***/
try{
$app = $client->CloseSession($token);
}catch(SoapFault $ex){
abort();
}
If any questions, don't hesitate to ask them here, I'll be glad to help as I had such problems figuring this out.

Related

Build correct SOAP Request Header (PHP)

I have to do requets to a SOAP API with PHP and I need the following SOAP-Header structure:
<soapenv:Header>
<ver:authentication>
<pw>xxx</pw>
<user>xxx</user>
</ver:authentication>
</soapenv:Header>
How can I build this header?
I tried
$auth = [
"ver:authentication" => [
"pw" => $this->pw,
"user" => $this->user
]
];
$options = [];
$options["trace"] = TRUE;
$options["cache_wsdl"] = WSDL_CACHE_NONE;
$options["compression"] = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP;
$client = new SoapClient("www.my-url.com/wsdl", $options);
$header = new SoapHeader("www.my-url.com", "authentication", $auth, false);
$client->__setSoapHeaders($header);
but it does not work. The respons is "failure" which I get, when the header structure is incorrect...
please help
the solution could be object driven. In the following code an example is given. Please keep in mind, that the following code is not testet.
class Authentication
{
protected $user;
protected $pw;
public function getUser() : ?string
{
return $this->user;
}
public function setUser(string $user) : Authentication
{
$this->user = $user;
return $this;
}
public function getPw() : string
{
return $this->pw;
}
public function setPw(string $pw) : Authentication
{
$this->pw = $pw;
return $this;
}
}
The above shown class is a simple entity, which contains two properties $user fpr the username and $pw for the password. Further it contains the getter and setter functions for retrieving or setting the values for the two properties.
For the next step just fill the class with data and store it in a SoapVar object.
$authentication = (new Authentication())
->setUser('Username')
->setPw('YourEncodedPassword');
$soapEncodedObject = new \SoapVar(
$authentication,
SOAP_ENC_OBJECT,
null,
null,
'authentication',
'http://www.example.com/namespace'
);
As you can see above, your authentication class will be stored as soap var object. It is encoded as soap object. The only thing you have to do is setting the namespace for this object. In your given example it is ver:. With this namespace prefix somewhere in your wsdl file a namespace is noted. You have to find out this namespace url and just replace the example url http://www.example.com/namespace with the right url noted in your wsdl.
The next step is setting this as soap header. That 's quite simple.
try {
$client = new SoapClient('http://www.example.com/?wsdl', [
'trace' => true,
'exception' => true,
'cache_wsdl' => WSDL_CACHE_NONE,
'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
]);
// set the soap header
$header = new SoapHeader('http://www.example.com/namespace', 'authentication', $authentication, false);
$client->setSoapHeaders($header);
// send the request
$result = $client->someWsdlFunction($params);
} catch (SoapFault $e) {
echo "<pre>";
var_dump($e);
echo "</pre>";
if ($client) {
echo "<pre>";
var_dump($client->__getLastRequest());
echo "</pre>";
echo "<pre>";
var_dump($client->__getLastResponse());
echo "</pre>";
}
}
As you can see it 's a bit different from your given example. Instead of an array it 's the soap encoded authentication object, that is given to the soap header class. For failure purposes there is a try/catch block around your soap client. In that case you can identify the error and if the client was initiated correctly, you can also see the last request and last response in xml.
I hope, that I helped you. ;)
I would strongly advise you 2 things:
Use a WSDL to PHP generator in order to properly construct your request. In addition, it will ease you the response handling. Everything is then using the OOP which is much better. Take a look to the PackageGenerator project.
Use the WsSecurity project in order to easily add your dedicated SoapHeader without wondering how to construct it neither.

Can't access Object in my Soap Client PHP

I'm learning how to implement Soap Web Services for a project but I'm having a bit of an issue with it. I access the client and have a method that calls the Server to get data from the database. The data coming from the database is being returned as an Object and then encoded to JSON. When I run it i get this error
SoapFault: Class 'Cow' not found in /home/ubuntu/workspace/V1Project/web_services/soap_client.php on line 10
But I tried requiring the class thinking it would "see" the Object was enfact there. But it still doesn't seem to work.
I have another method in the database that gets the data and just puts it into an array and encodes it into JSON and works fine.
Soap_Client.php
<?php
require_once('../controller/classes/Cow.php');
$option = array('location' => 'https://name_of_direct/soap_service.php',
'uri' => 'http://localhost');
try {
$client = new SoapClient(null, $option);
echo $client->getCow(40);
} catch (SoapFault $ex){
var_dump($ex);
}
?>
And...
Soap_Service.php
<?php
require_once('../model/DBController.php');
$option = array('uri' => 'http://localhost/');
$server = new SoapServer(null, $option);
$server -> setObject(new DBController());
$server -> handle();
?>
Thank you for reading and any tips or help is hugely appreciated!

PHP SoapRequest: get response

I am trying to implement a soaprequest and making the call does seem to work. The only problem is: I don't know how to receive the response data. My code looks like this:
$auth = array(
'UsernameToken' => array(
'Username' => 'xxx',
'Password' => 'yyyy'
)
);
$header = new SoapHeader('xs','Security',$auth, 0);
$client->__setSoapHeaders($header);
$client->__setLocation('http://example.com/test.php');
$params = array(
...
'trace' => 1,
'cache_wsdl' => 0
);
try {
$response = $client->getSomeData($params);
}catch(Exception $e){
echo "Exception: ".$e->getMessage();
}
print_r($response);
This results in an empty page, because $response is empty. But the test.php file is called (I tried with a simple mail() command and it sends the mail every time I call the page with the soapclient).
So I guess the soap response is somehow sent to the test.php file - right? How do I get it? If I do not set the location, I get a nullpointerexception, so I have to do that. I tried
$client->__getLastResponse()
that's empty too.
What can I do, how do I get the soap response data? Any hints would be appreciated. Thank you!

PHP SOAP Client Error for none build-in functions

There is a wcf server and I am trying to connect it and send requests.
The code is :
$url = "http://serverip:8080/example.svc?wsdl";
$params = array(
'Username' => 'username',
'Password' => 'password'
);
$client = new SoapClient($url);
var_dump($client->__getTypes()); //it works
$result = $client->Login($params); //gives error
But everytime I am getting internal server error. I spend 5 days and searhed all the web and tried all different methods but I am always getting internal server error. Error is below :
protected 'message' => string 'The server was unable to process ...
private 'string' (Exception) => string '' (length=0) ...
If I use SOAP UI I can send and get data or if I call "$client->__getTypes()" from php server, I get types. But if I call implemented functions with PHP it doesn't work. Are there anyone to help me?
Thanks a lot,
Perhaps you should pass the parameters as object as in the following example
try {
$client = new SoapClient('http://serverip:8080/example.svc?wsdl');
$params = new stdClass();
$params->Username = 'Username';
$params->Password = 'Password';
$client->Login($params);
} catch (SoapFault $e) {
// error handling
}

Calling WCF with PHP -- variable structures

I have a WCF Service written in .Net 4.0 that accepts two parameters. One is a complex type consisting of User, MerchantName, and Password, the second variable is an int. The service returns a third complex type.
It's structure looks like the following:
//*C# Code *
public sub AccountData Log(Login LoginData, int AccountID)
{
//do stuff here
}
Using SoapClient and removing the int AccountID from the C# service, I can pass the complex data in and parse through the complex data output succesfully. Adding the AccountID parameter, breaks the soap call. I can't seem to compound the variables into one array in a fashion that WCF will accept.
The question is how to form the array to pass in the call?
I have tried the following:
//****Attempt one *******
$login = array('MerchantName' => 'merchantA',
'User' => 'userA',
'password' => 'passwordA');
$account = '68115'; //(also tried $account = 68115; and $account = (int)68115;)
$params = array('LoginData' => $login, 'AccountID' => $account);
$send = (object)$params; //Have tried sending as an object and not.
$client = new SoapClient($wsdl);
$client->soap_defencoding = 'UTF-8';
$result = $client->__soapCall('Log', array($send);
var_dump($send);
echo("<pre>");
var_dump($result);
The latest attempt was to class the variables but I got stuck when tring to form into the $client call.
class LogVar
{
public $MerchantName;
public $User;
public $Password;
}
class AccountID
{
public $AccountID;
}
$classLogin = new LogVar();
$classLogin->MerchantName = 'merchantA';
$classLogin->User = 'userA';
$classLogin->Password = 'passwordA';
$classAccount = new AccountID();
$classAccount->AccountID = '68115';
//How to get to $client->__soapCall('Log', ???????);
P.S. I'm a .Net coder, please be kind with the PHP explanations... Also NuSoap didn't seem much better, however it may have undiscovered ways of dealing with complex types.
This worked for me with standard SoapClient:
$client = new SoapClient($wsdl, array('trace' => true));
$data = $client->Log(array('AccountID' => 23, 'LoginData' => array('User' => '123', 'Password' => '123', 'MerchantName' => '123')));
// echo $client->__getLastRequest();
var_dump($data);
You can display the last request XML and compare it with what a WCF client is generating. This is how I figured it out: I generated a WCF client, inspected the XML message generated by it and compared to $client->__getLastRequest.
Note: You can call the method by its name on a SoapClient rather than use $client->__soapCall('operationName')

Categories