I rewrite soap client file using Zend framework.
This is old method. it is working.
function getBassaService(){
global $service;
$h="127.0.0.1";
$p="8000";
if($service==null){
$service = new SoapClient("/test/php/bassa.wsdl", array(
"soap_version" => SOAP_1_2,
"trace" => 1,
"exceptions" => 1,
"location" => "http://".$h.":".$p));
}
return $service;
}
function getAllDownloads(){
global $service;
$client = getService();
try{
$results = $client->__soapCall("list-all", array());
}catch(SoapFault $e){
print($e->faultstring);
}
return $result;
}
This is my new code. I use Zend_Soap_Client.
const HOST = "127.0.0.1";
const PORT = "8095";
protected $_client;
public function __construct()
{
$this->_client = new Zend_Soap_Client(APPLICATION_PATH ."/services/bassa.wsdl",
array(
"soap_version" => SOAP_1_2,
"uri" => "http://". self::HOST .":". self::PORT
)
);
}
public function getAllDownloads()
{
$result = $this->_client->list-all();
return $result;
}
My soap server has list-all method. I want soap call to that method. But following error has occurred. Because method name has hyphen.
Notice: Undefined property: Zend_Soap_Client::$list in /home/dinuka/workspace/testzend/application/services/SoapClient.php on line 57
Fatal error: Call to undefined function all() in /home/dinuka/workspace/testzend/application/services/SoapClient.php on line 57
How i fixed it. Please help me.
strange. that's should work. it might be a a bug in ZF framework. maybe it's trying to convert the function name into a camel case function name with variables.
Try to use the magic function directly by calling:
$this->_client->__call('list-all', array('param1' => $param1))
Related
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.
I try to create a Soap Server in CakePHP 3 but if I want to connent with my client i become error's every time.
I set up the server in a function:
public function view($id) {
$connection = ConnectionManager::get('default');
$user = $connection->execute('SELECT * FROM users WHERE id='.'"'.$id.'"')->fetchAll('assoc');
$obj = new Post;
$this->viewBuilder()->layout = false;
$this->autoRender = false;
ini_set("soap.wsdl_cache_enabled",0); //disable wsdl cache
$server = new SoapServer(null, array(
'uri' => 'http://localhost/test-uri',
'encoding'=>'UTF-8'
)
);
$server->setObject($obj);
$server->handle();
}
in a model I create this function:
namespace App\Model\Entity;
use Cake\ORM\Entity;
use Cake\Utility\Xml;
class Post {
function testfunktion($param){
return $param;
}
}
my client script show this:
$soap = new SoapClient(
null,
array(
"location" => "http://localhost/shop_system/users/view/2",
"uri" => "http://test-uri",
"trace" => 1
)
);
try {
$product = $soap->testfunktion("Michael");
} catch (SoapFault $e) {
echo $e;
print($soap->__getLastResponse());
}
and this is my output:
SoapFault exception: [Client] looks like we got no XML document in C:\xampp\htdocs\shop_system\webroot\client.php:15 Stack trace: #0 C:\xampp\htdocs\shop_system\webroot\client.php(15): SoapClient->__call('testfunktion', Array) #1 C:\xampp\htdocs\shop_system\webroot\client.php(15): SoapClient->testfunktion('Michael') #2 {main}
Notice (8): Undefined index: HTTP_ACCEPT_LANGUAGE [APP/Controller\UsersController.php, line 22]Michael
i dont know what i must do by this error
Can anyone tell me why the SOAP client is not being re-used? It keeps getting initialized where it should have been reused from the last call.
When I print out the SOAP client object after it was initialized it is there but it is forgotten at the next call.
So the php script keeps initializing the connection.
My code:
class EcoAPI {
private $client;
public function getClient() {
if (empty($this->client)) {
echo "<br>initializing...";
$this->initClient();
}
return $this->client;
}
private function initClient() {
$settingsOld = Settings::GetOld();
$this->client = new SoapClient("https://api.e-conomic.com/secure/api1/EconomicWebservice.asmx?WSDL", array("trace" => 1, "exceptions" => 1));
$this->client->ConnectWithToken(array('token' => $settingsOld->economic_token_secret, 'appToken' => $settingsOld->economic_token_app));
}
}
I connect by:
$ecoApi = new EcoAPI();
$result = $ecoApi->getClient()->Account_GetVatAccount(array('accountHandle' => (object) array('Number' => (string) $VatAccount)));
Every time you're creating a new EcoAPI object, it won't have any SOAP client information. Using $ecoApi->getClient()->... throughout your code SHOULD work as long as you're using injecting the same $ecoApi object.
If you want to ensure that every EcoAPI object has the same connection object, no matter what, you could try making the client a static property with static methods to manipulate the SOAP object.
class EcoAPI {
static private $client;
static public function getClient() {
if (empty(self::$client)) {
echo "<br>initializing...";
self::initClient();
}
return self::$client;
}
static private function initClient() {
$settingsOld = Settings::GetOld();
self::$client = new SoapClient("https://api.e-conomic.com/secure/api1/EconomicWebservice.asmx?WSDL", array("trace" => 1, "exceptions" => 1));
self::$client->ConnectWithToken(array('token' => $settingsOld->economic_token_secret, 'appToken' => $settingsOld->economic_token_app));
}
}
And connect by:
$result = EcoAPI::getClient()->Account_GetVatAccount(array('accountHandle' => (object) array('Number' => (string) $VatAccount)));
Granted, I would advise against using static objects and methods and it can lead to tight coupling. The best method, in my opinion, is injecting your instantiated objects on an as-needed basis.
I am trying to load a model to a webservice (Nusoap) as follows:
Controller:
class Addition extends CI_Controller{
public function Addition(){
parent::__construct();
$ns = base_url().'addition/';
$endpoint = base_url().'addition/';
$this->load->library("nusoap_library"); // load nusoap toolkit library in controller
$this->nusoap_server = new soap_server(); // create soap server object
$this->nusoap_server->configureWSDL("SMS SOAP", $ns, $endpoint); // wsdl cinfiguration
$this->nusoap_server->wsdl->schemaTargetNamespace = $ns; // server namespace
// REGISTER FUNCTIONS
$input_array = array ('var1' => "xsd:string", 'var2' => "xsd:string"); // "addnumbers" method parameters
$return_array = array ("var3" => "xsd:int", 'var4' => "xsd:string");
$this->nusoap_server->register('send', $input_array, $return_array, "urn:SOAPServerWSDL", "urn:".$ns."send", "rpc", "encoded", "My Addition WS");
}
function index(){
function send($var1, $var2){
$this->load->model('mymodel'); // THIS IS MY MODEL
$data['var1'] = $this->mymodel->addnumbers($var1, $var2);
$data['var2'] = "yes";
return $data;
}
$this->nusoap_server->service(file_get_contents("php://input"));
}
}
The problem is that if I take out the model and just add directly, it will work perfectly, but with the model it returns nothing.
Any help will be greatly appresiated.
I think I solved my own question.
Apparently you cannot invoke directly the model. A way to do it is the following:
class Addition extends CI_Controller{
public function Addition(){
parent::__construct();
$ns = base_url().'addition/';
$endpoint = base_url().'addition/';
$this->load->library("nusoap_library"); // load nusoap toolkit library in controller
$this->nusoap_server = new soap_server(); // create soap server object
$this->nusoap_server->configureWSDL("SMS SOAP", $ns, $endpoint); // wsdl cinfiguration
$this->nusoap_server->wsdl->schemaTargetNamespace = $ns; // server namespace
// REGISTER FUNCTIONS
$input_array = array ('var1' => "xsd:string", 'var2' => "xsd:string"); // "addnumbers" method parameters
$return_array = array ("var3" => "xsd:int", 'var4' => "xsd:string");
$this->nusoap_server->register('send', $input_array, $return_array, "urn:SOAPServerWSDL", "urn:".$ns."send", "rpc", "encoded", "My Addition WS");
}
function index(){
function send($var1, $var2){
$CI =& get_instance();
$CI->load->model('mymodel'); // THIS IS MY MODEL
$data['var1'] = $CI->mymodel->addnumbers($var1, $var2);
$data['var2'] = "yes";
return $data;
}
$this->nusoap_server->service(file_get_contents("php://input"));
}
I know this may not be the best solution but it works perfectly and you are able to load any model using Codeigniter Framework with Nusoap.
Hope this helps as future reference.
If anyone has a better way to load the model please let us know.
i am getting this error when trying to make a soap call.
The SOAP action specified on the message, '', does not match the HTTP SOAP Action.
When i call $service->SearchTouristItems($sti); (this function is further below) i get the above error and i have no idea why.
The below is the code i am using.
// i used http://www.urdalen.no/wsdl2php/ to create TCS2Service which extends SoapClient
$service = new TCS2Service() ;
$sd = new ServiceDescriptor;
$sd->UniqueIdentifier = 'xxxxxxxxx-xxxxx-xxxx-xxxxx-xxxxxx';
$stic = new SearchTouristItemCriteria;
$stic->SearchString = array ('dublin') ;
$sti = new SearchTouristItems;
$sti->searchTouristItemCriteria = $sd;
$sti->serviceDescriptor = $stic;
$result = $service->SearchTouristItems($sti);
echo "<pre>";
print_r($result);
echo "</pre>";
SearchTouristItems looks like this
/**
*
*
* #param SearchTouristItems $parameters
* #return SearchTouristItemsResponse
*/
public function SearchTouristItems(SearchTouristItems $parameters) {
return $this->__soapCall('SearchTouristItems', array($parameters), array(
'uri' => 'http://tempuri.org/',
'soapaction' => ''
)
);
}
this is the initilization of the client
public function TCS2Service($wsdl = "http://www.example.com/services/TCS2Service.svc", $options = array( 'soap_version' => SOAP_1_2,
'exceptions' => true,
'trace' => 1,
'cache_wsdl' => WSDL_CACHE_NONE,)) {
foreach(self::$classmap as $key => $value) {
if(!isset($options['classmap'][$key])) {
$options['classmap'][$key] = $value;
}
}
parent::__construct($wsdl, $options);
}
Not sure though but what is the value of 'soapaction' => '' in your code is replaced with the provided parameter. I do not have that experience calling web services with PHP so just gave it a thought.
I think your ws-addressing is not turned on. Please turn on the ws-
addressing and check again.
What I would do :
check if the SOAP action is well defined in the WSDL: look for address location="
try another WSDL to php converter
send the WSDL url so I can try it by my side