Does Ksoap2 require that a web service produce a wsdl? - php

I have successfully written an Android app which calls an asp.net web service using Ksoap2. I now want to migrate the app to use a PHP web service. I have successfully migrated the web service over to a native PHP web service (and tested it using a PHP client) but I'm having trouble calling it using KSOAP. One thought that struck me was that the native PHP web service was not generated using a wsdl, and is not able to automatically generate a wsdl.
Does ksoap2 require a wsdl to successfully call a web service method?
The asp.net web service is located at http://mycomputer/AlumLocateService/Service.asmx
For the succesful call to asp.net service:
private static final String NAMESPACE = "http://mycomputer/";
private static final String URL = "http://mycomputer/AlumLocateService/Service.asmx";
private static final String METHOD_NAME_3 = "FindCloseDetails";
private static final String SOAP_ACTION_3 = NAMESPACE + METHOD_NAME_3;
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME_3);
PropertyInfo pi = new PropertyInfo();
pi.setName("userid");
pi.setValue(userid);
pi.setType(string.class);
request.addProperty(pi);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION_3, envelope);
//Parse Response
Object myResult = envelope.bodyIn;
SoapObject resultsRequestSOAP = (SoapObject) myResult;
String[] results = getStringArrayResponse(resultsRequestSOAP, null);
return results;
The PHP service is located at http://mycomputer/PHPTest/testserver.php and replicates the methods of the asp.net web service. I had hoped thta all I woudl need to do would be to change the following
private static final String URL = "http://mycomputer/PHPTest/testserver.php";
and remove the line
envelope.dotNet = true;
but when I do that i get "XmlPullParserException: unexpected type (position END_DOCUMENT null...." when the androidHttpTransport.call(SOAP_ACTION_3, envelope) call is made.

One I had changed to using a PHP Zend_Soap_Server I had to change the last part of my Android code to:
Object myResult = envelope.getResponse();
String[] results = null;
if (myResult instanceof Vector)
{
Vector<Object> myVector = (Vector<Object>) myResult;
results = new String[myVector.size()];
for (int i = 0; i< myVector.size();i++){
results[i] = myVector.elementAt(i).toString();
}
}
return results;

Related

Symfony Mailer Exchange mail server

Today I'm trying to connect my Symfony application to a local mail server that running as Microsoft Exchange server.
First, before switching to Symfony my web project was developed with Asp.NET, for some personal reasons I refund the project under Symfony.
In C# this code was working correctly :
public static void MailSender(string server, string fromDisplayName, string fromMailAddress, List<List<KeyValuePair<string,string>>> tos, string subject, string body, List<string> attachments = null, List<List<KeyValuePair<string,string>>> ccs = null, List<List<KeyValuePair<string,string>>> bccs = null)
{
using (MailMessage mailMessage = new MailMessage())
{
mailMessage.From = new MailAddress(fromMailAddress, fromDisplayName);
foreach(List<KeyValuePair<string, string>> to in tos){
mailMessage.To.Add(new MailAddress(to[1].Value.ToString(), to[0].Value.ToString()));
}
if (ccs != null){
foreach(List<KeyValuePair<string, string>> cc in ccs){
mailMessage.CC.Add(new MailAddress(cc[1].Value.ToString(), cc[0].Value.ToString()));
}
}
if (bccs != null){
foreach(List<KeyValuePair<string, string>> bcc in bccs){
mailMessage.CC.Add(new MailAddress(bcc[1].Value.ToString(), bcc[0].Value.ToString()));
}
}
mailMessage.Subject = subject;
mailMessage.Body = body;
mailMessage.IsBodyHtml = true;
if (attachments != null)
{
foreach (string attachment in attachments)
mailMessage.Attachments.Add(new Attachment(attachment));
}
using (SmtpClient smtpClient = new SmtpClient(server))
{
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
smtpClient.UseDefaultCredentials = true;
smtpClient.Send(mailMessage);
}
}
}
The server url was in the format: myserver.domain.tld.
Also it used the Windows Integrated Authentication.
How can I configure PHP or Symfony (or both) to work with my local Exchange mail server ?
I tried to use this type of url in MAILER_DSN variable:
smtp://user:pass#myserver.domain.tld (user as email address with '%40' for '#' character.
Thanks.
Sorry for this question cause Its a mistake from me, I put MAILER_DSN=smtp://server.tld:25
Also, I commented a line into config/packages/messenger.yaml
this line: Symfony\Component\Mailer\Messenger\SendEmailMessage: async
This second option solve my problem.
If you had another option, I'm aware about it!
Thks.

PHP Soap Client does not send all object properties in a webservice call

I try to implement a webservice Client using php and got stuck...
I'm using an existing webservice called metadataservice with a known wsdl.
I'll use wsdl2phpgenerator to create the php classes for the datatypes and the Service itself.
Using one of the Webservice Methods (addMetadataToObject), I have to send an Array of objects to the Server.
There is a base class:
class AssetInfo
{
public $dataFieldId = null;
public $dataFieldName = null;
public $dataFieldTagName = null;
public function __construct($dataFieldId, $dataFieldName, $dataFieldTagName)
{
$this->dataFieldId = $dataFieldId;
$this->dataFieldName = $dataFieldName;
$this->dataFieldTagName = $dataFieldTagName;
}
}
and a derived class Holding string values (there are also other derived classes for Longs etc.):
class StringAssetInfo extends AssetInfo
{
public $value = null;
public function __construct($dataFieldId, $dataFieldName,$dataFieldTagName, $value)
{
parent::__construct($dataFieldId, $dataFieldName, $dataFieldTagName);
$this->value = $value;
}
}
For the call of Metadataservice->addMetadataToObject there is also a addMetadataToObject defined:
class addMetadataToObject
{
public $objectId = null;
public $objectType = null;
public $assetInfos = null;
public function __construct($objectId, $objectType)
{
$this->objectId = $objectId;
$this->objectType = $objectType;
}
}
The property $assetInfos should hold an Array of AssetInfo objects. wdsl2phpgenerator creates a class for my MetadataService which is derived from SoapClient. This class provides all the avialable Methods for this Service. Here I only show the addMetadataToObject Method:
public function addMetadataToObject(addMetadataToObject $parameters)
{
return $this->__soapCall('addMetadataToObject', array($parameters));
}
My Code does:
// Define the Data
$ServiceOptions = [];
$AssetInfos = [];
$AssetInfo = new StringAssetInfo(2, "TitleName", "TitleName","New Title Name);
array_push($AssetInfos, $AssetInfo);
// Create the Service
$Service = new MetadataService($ServiceOptions, getServiceWSDL($Options, "MetadataService"));
$Service->__setSoapHeaders(getGalaxySoapHeader($Options));
$NewMetaData = new addMetadataToObject(61755, "ASSET");
$NewMetaData->assetInfos = $AssetInfos;
// Call the Service
$failedAssets = $Service->addMetadataToObject($NewMetaData);
The call throws a Soap Exception that a value could not be extracted. Which makes me wonder. I started to monitor the traffic to the Soap Server using wireshark and yes....there is no value anymore as defined in the StringAsset Info Class...Here is the Soap Body shown by wireshark:
<SOAP-ENV:Body>
<ns1:addMetadataToObject>
<objectId>61755</objectId>
<objectType>ASSET</objectType>
<assetInfos>
<dataFieldId>2</dataFieldId>
<dataFieldName>TitleName</dataFieldName>
<dataFieldTagName>TitleName</dataFieldTagName>
</assetInfos>
</ns1:addMetadataToObject>
Id</SOAP-ENV:Body>
I would expect a tag New Title Name. But ist gone. When I checked the $NewMetaData object in my Code or the $Parameter object in $Service->addMetadataToObject I can see that the property "Value" is defined and set.
For me it seems, that the call to
return $this->__soapCall('addMetadataToObject', array($parameters));
only accepts the properties of the base class AssetInfo but not the properties from the derived class StringAssetInfo.
I also changed the Code to use an Array (instead of an object) for $AssetInfo:
$AssetInfo = array("dataFieldId"=>2, "dataFieldName"=>"TitleName","dataFieldTagName"=>"TitleName, "value"=>"New Title Name");
But without any change. It seems that we have here some Kind of runtime type conversion or type alignment but I can't see the reason of this. I'm still new to webservices at all and also on php (however I have to use both for the Moment:-)
Can anybody comment or give me a hint what's happening here?
I was able to realize it by using Arrays and soapvars, Please note my comments in the code:
$ServiceOptions = [];
$AssetInfos = [];
// I have to use an Array because the Server depends on the order of the properties. I wasn't able to define expected order using the existing objects but with arrays
$AssetInfo = array("dataFieldId"=>2, "dataFieldName"=>"TitleName","dataFieldTagName"=>"TitleName, "value"=>"New Title Name");
// instead of pushing the Array directly, I create an instance of an SoapVar, pass the Array as data and set the Encoding, the expected type and the Namespace uri
array_push($AssetInfos, new SoapVar($AssetInfo, SOAP_ENC_OBJECT, "StringAssetInfo", "http://metadataservice.services.provider.com"));
array_push($AssetInfos, $AssetInfo);
// Create the Service
$Service = new MetadataService($ServiceOptions, getServiceWSDL($Options, "MetadataService"));
$Service->__setSoapHeaders(getGalaxySoapHeader($Options));
$NewMetaData = new addMetadataToObject(61755, "ASSET");
$NewMetaData->assetInfos = $AssetInfos;
// Call the Service
$failedAssets = $Service->addMetadataToObject($NewMetaData);
This produced the expected Output in the Soap Body (and also added some namespaces to the Soap envelope
<SOAP-ENV:Body>
<ns1:addMetadataToObject>
<objectId>61755</objectId>
<objectType>ASSET</objectType>
<assetInfos xsi:type="ns1:StringAssetInfo">
<dataFieldId>2</dataFieldId>
<dataFieldName>TitleName</dataFieldName>
<dataFieldTagName>TitleName</dataFieldTagName>
<value>New Titel Name 1146</value>
</assetInfos>
</ns1:addMetadataToObject>
</SOAP-ENV:Body>

PHP rest API returning JSON for webpages

I am developing a PHP restful API which is returning a JSON response. This is currently for native mobile app consumption (iOS/Android).
My question, is it possible to use the same restful API for website consumption? or do I need to support HTML response from the restful API as well as JSON? How do you get a JSON response from a web service to display as a webpage? or do I need to implement output formatters as part of the framework to respond as HTML when required?
I have tried to search for answers to this question but I couldn't find any useful answer.
Emm... As theory, for example you can make it like this:
class MyOutput
{
const CTX_HTML = 1;
const CTX_JSON = 2;
//const CTX_XML = 3;
//const CTX_CLI = 4;
//const CTX_ETC = N;
private $_data = null;
public function __construct()
{
$this->_data = new StdClass();
}
public function __set($prop, $value)
{
$this->_data->{$prop} = $value;
}
public function render($context)
{
if ($context == self::CTX_JSON) {
header('Content-Type: application/json');
echo json_encode($this->_data);
} else {
header('Content-Type: text/html');
// TODO extract/pass data into layout/template
}
}
}
$Output = new MyOutput();
$Output->foo = 1;
$Output->bar = 2;
$Output->render(MyOutput::CTX_JSON);
$Output->render(MyOutput::CTX_HTML);
But i think API should be place on separated host. Because this is different applications.
you can create API that returns XML and from XML using XSL construct HTML
This link gonna be helpful:
http://www.htmlgoodies.com/beyond/xml/converting-xml-to-html-using-xsl.html

PHP SOAPClient WCF Error sending parameters

I'm working on a Webservice using PHP SoapClient.
The webservice url is: http://web.abaseguros.com/AutoConnect/ACCatalogos.svc?wsdl
And here is my code:
<?php
ini_set("soap.wsdl_cache_enabled", "0");
$pin = new SoapClient("http://web.abaseguros.com/AutoConnect/ACCatalogos.svc?wsdl");
class Token {
var $usuario;
var $password;
function Token($user,$pass) {
$this->usuario = $user;
$this->password = $pass;
}
}
//User and Password for the token object
$Token = new Token('usuarioWCF','Pa$$w0rd');
//XML 'Entrada' String
$Entrada = "<CAT><NEG>5786</NEG></CAT>";
$result = $pin->ObtenerMarcas($Token,$Entrada);
But PHP prints out the following error message:
Fatal error: Uncaught SoapFault exception: [a:DeserializationFailed] when i execute the script.
The company gave me a sample code written on C#
private void Obtener_Catalogo_ABASeguros()
{
string strEntrada, strSalida;
strEntrada = “<CAT><NEG>5786</NEG></CAT>“; +
ACCatalogosClient proxy = new ACCatalogosClient();
Token token = new Token();
token.usuario = "usuarioWCF";
token.password = "Pa$$w0rd";
try
{
strSalida = proxy.ObtenerMarcas(token, strEntrada);
}
catch (FaultException<Error> ex)
{
txtCotSalida.Text = string.Format("Ocurrio un error en el WCF:\n " +
"Origen: {0}\n "+
"Mensaje: {1}\n "+
"Stack: {2}", ex.Detail.Origen, ex.Detail.Mensaje, ex.Detail.StackTrace);
}
But I'm still unabled to understand how parameters are sent on both languages.
Any Help?
Your Soap client does not know how to deserialize the object Token. You need to convert that token object into a associate array and use that array as parameter to the operation instead.
$pin->ObtenerMarcas(get_object_vars($Token),$Entrada);
I am afraid even you get this error cleared, you will not be successful in working with the service yet. It looks like the a token is required in the soap header instead. the C code you put does not show you everything, it has the implementation encapsulated inside the Proxy class. You need to have a read the documentation is there's any, otherwise you will have to read the imported wsdl files embedded in your provided global wsdl link.

How to execute a web service using php

I need to execute a web service from a php page
The web service is located in the following url
https://www.agemni.com/AgemniWebservices/service1.asmx
The Web Service uses a SOAP protocol to exchange messages.
The WSDL info can be located at https://www.agemni.com/AgemniWebservices/service1.asmx?WSDL
The function in that service that we need to use is ValidateEntity
//ValidateEntity("username", "password", "companyID", 2, keys, values)
So , how can i execute this web service and get result from my php page
A simple example, hope it helps...
$service1 = new SoapClient('https://www.agemni.com/AgemniWebservices/service1.asmx');
//here you instanciate your object with those properties
$entity = new Entity();
$entity->strUsername = 'José';
$entity->strPassword = '123';
$entity->strCompanyName = 'Somethin';
$entity->0 //because your type is int
$res = $service1->ValidateEntity($entity);//here you send the information to your service's method, if I'm not mistaken, it must be a object
$res->ValidateEntityResult;//this is the return of your service.
As I said, it is really simple but works.
See soap calls help from php.net:
http://www.php.net/manual/en/soapclient.soapcall.php
You need to use PHP's SOAP libraries...
http://www.php.net/manual/en/soapclient.soapcall.php
For https WebServices you need to enable openssl extension. The WS use .net it means that the class use type hinting so you need to create the ValidateEntity class, here's the code:
$ws = new soapclient('https://www.agemni.com/AgemniWebservices/service1.asmx?wsdl');
class ValidateEntity {
public $strUsername,
$strPassword,
$strCompanyName,
$objecttype;
}
$parameters = new ValidateEntity();
$parameters->strUsername = 'username';
$parameters->strPassword = 'password';
$parameters->strCompanyName = 'company';
$parameters->objecttype = 1;
echo '<pre>';
print_r($ws->ValidateEntity($parameters));
echo '</pre>';

Categories