Deserialize WCF web service request in PHP - php

I have a WCF web service with a Login operation taking a company name, user name and password as the three parameters. I am trying to create a PHP client app to communicate with this service. No matter what I pass to the Login operation I get the following error:
OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'Login' and namespace ''. Found node type 'Element' with name 'parameters' and namespace ''
My client app:
<?php
try
{
$client = new SoapClient("https://somewhere.com/DataServiceRxPublic.svc?wsdl");
//$params = array(
// 'parameters' => array(
// 'Param' => array(
// array('Name' => 'loginCompany', 'Value' => 'XXX'),
// array('Name' => 'loginId', 'Value' => 'XXX'),
// array('Name' => 'loginPwd', 'Value' => 'XXX')
//)));
//$params = array(
// 'Login' => array(
// array('Name' => 'loginCompany', 'Value' => 'XXX'),
// array('Name' => 'loginId', 'Value' => 'XXX'),
// array('Name' => 'loginPwd', 'Value' => 'XXX')
//));
//$params = array(
// 'Login' => array(
// 'parameters' => array(
// array('Name' => 'loginCompany', 'Value' => 'XXX'),
// array('Name' => 'loginId', 'Value' => 'XXX'),
// array('Name' => 'loginPwd', 'Value' => 'XXX')
//)));
//$params = array(
// array('Name' => 'loginCompany', 'Value' => 'XXX'),
// array('Name' => 'loginId', 'Value' => 'XXX'),
// array('Name' => 'loginPwd', 'Value' => 'XXX')
//);
$params = array(
'loginCompany' => 'XXX',
'loginId' => 'XXX',
'loginPwd' => 'XXX'
);
$obj->loginCompany = 'XXX';
$obj->loginId = 'XXX';
$obj->loginPwd = 'XXX';
//$result = $client->Login($obj);
//$result = $client->Login($params);
}
catch (Exception $e)
{
print_r($e);
}
}
?>
$params being the different array permutations I've based off several different examples online.
Any help is appreciated.

The error message is telling you that there should have been something named "Login", but was named "parameters".
Go get SoapUI and with your WSDL follow the steps I described here to debug what you are actually sending. If you cannot compare what the service expects vs. what you are sending, this will be way too much trial-and-error.
If you need more external help, we'd need the WSDL resource - without it, nobody knows which request structure is expected.

Turns out I needed to extend the SOAPClient and override the __doRequest() method to replace the mismatched soap headers.

I managed to fix this error by modifying service namespace on server side.
[ServiceContract(Name="Service", Namespace = "https://sample.eu")]
Namespace was empty before.

Related

S3 PutBucketWebsite AWS PHP SDK

I would like to create a pure redirect bucket in AWS S3, I am sure the s3client is operational without problems.
$subdomain = 'test.example.com';
$redirectURL = 'https://www.somedomain.com/redirect?someparam';
$bucketID = $s3->createBucket(['Bucket' => $bucket ]);
$arg = array(
'Bucket' => $bucket, // REQUIRED
'WebsiteConfiguration' => array( // REQUIRED
'ErrorDocument' => array( 'Key' => 'err.html', ),
'IndexDocument' => array( 'Suffix' => 'index.html', ),
'RedirectAllRequestsTo' => array('HostName' => $redirectURL, ),
'RoutingRules' => array(
array(
'Redirect' => array(
'HostName' => $redirectURL,
'HttpRedirectCode' => '301',
),
),
),
),
);
$result = $s3->putBucketWebsite($arg);
However, it output following error even i tried to change some other settings.
> Request ID E00C517E4F812581
Error Type client
Error Code MalformedXML
I wonder if there's any hidden setting I need to add on it.
RedirectAllRequestsTo is mutually exclusive with ErrorDocument, IndexDocument, and RoutingRules. If you are redirecting everything elsewhere, there would be no evaluation of the error or index documents, nor would the routing rules be applicable.
RedirectAllRequestsTo
Describes the redirect behavior for every request to this bucket's website endpoint. If this element is present, no other siblings are allowed.
Type: Container
Ancestors: WebsiteConfiguration
http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTwebsite.html
finally i got the solution by this, it works
$subdomain = 'test.example.com';
$protocol = 'https';
$redirectURL = 'www.somedomain.com/redirect?someparam';
$bucketID = $s3->createBucket(['Bucket' => $bucket ]);
$arg = array(
'Bucket' => $bucket,
'WebsiteConfiguration' => array(
'RedirectAllRequestsTo' => array('HostName' => $redirectURL, 'Protocol'=>$protocol),
),
);
$result = $s3->putBucketWebsite($arg);

aws sdk validation error must be type object

I'm trying to create a record set with the aws sdk and I'm getting this validation error:
Validation errors: [ChangeBatch][Changes][0][Change][ResourceRecordSet][ResourceRecords][Value][ResourceRecord] must be of type object
My code looks like this:
$result = $r53->changeResourceRecordSets(array(
'HostedZoneId' => 'XXXXXXXXXXXXXXX',
'ChangeBatch' => array(
'Changes' => array(
array(
'Action' => 'CREATE',
'ResourceRecordSet' => array(
'Name' => 'psion',
'Type' => 'CNAME',
'ResourceRecords' => array(
'Value' => 'example.com'
),
),
'Change' => array(
'ResourceRecordSet' => array(
'ResourceRecords' => array(
'Value' => array(
'ResourceRecord' => $aws->get('Route53'),
),
),
),
),
),
),
),
));
Any idea what the validation error means?
Validation errors: [ChangeBatch][Changes][0][Change][ResourceRecordSet][ResourceRecords][Value][ResourceRecord] must be of type object.
By type "object", it means an associative array. This is a validation message bubbling up from the Guzzle layer.
Here are the API docs for Route53Client::changeResourceRecordSets(), which shows an example of how the request should look when it is formatted correctly.
That whole array you have under the 'Change' key is not correct at all.

SOAP 4 set_relationship not working

After battling for getting more than 20 entries with get_entry_list, i'm now trying to use the SOAP API on SugarCRM 6.5 to set a relationship between two elements, created from a form on the user-land website.
The set_relationship method is described as following in the devs blog :
$response = set_relationship(session, module_name, module_id, link_field_name, related_ids, name_value_list, delete);
So here is the code which handles the request, assuming that another part of the code handles the security.
$values = array( 'id_frame' => $_POST['id_frame'],
'id_battery' => $_POST['id_battery'],
'reseller' => $_POST['reseller'],
'date_purchase' => $_POST['date_purchase'],
'products_versionning' => $_POST['product_purchased'],
'first_name' => $_POST['first_name'],
'last_name' => $_POST['name'],
'phone_home' => $_POST['phone'],
'email' => $_POST['email'],
'primary_address_street' => $_POST['address'],
'primary_address_street_2' => $_POST['address2'],
'primary_address_street_city' => $_POST['city'],
'primary_address_street_postalcode' => $_POST['zip'],
);
try{
$prod_register = $soapClient->set_entry(
$sessid,
'myco_product_register',
array( array('name' => 'id_frame', 'value' => $values['id_frame']),
array('name' => 'id_battery', 'value' => $values['id_battery']),
array('name' => 'date_purchase', 'value' => $values['date_purchase']),
array('name' => 'first_name', 'value' => $values['first_name']),
array('name' => 'last_name', 'value' => $values['last_name']),
array('name' => 'phone_home', 'value' => $values['phone_home']),
array('name' => 'email', 'value' => $values['email']),
array('name' => 'primary_address_street', 'value' => $values['primary_address_street']),
array('name' => 'primary_address_street_city', 'value' => $values['primary_address_street_city']),
array('name' => 'primary_address_street_postalcode','value' => $values['primary_address_street_postalcode']),
array('name' => 'description','value' => "Modèle : " . $values['products_versionning'] . "\nAcheté le " . $values['date_purchase'] . " à " . $values['reseller']),
)
);
$client = $soapClient->set_entry(
$sessid,
'Accounts',
array( array('name' => 'name', 'value' => $values['first_name'] . ' ' . $values['last_name']),
array('name' => 'billing_address_street', 'value' => $values['primary_address_street']),
array('name' => 'billing_address_city', 'value' => $values['primary_address_street_city']),
array('name' => 'billing_address_postalcode', 'value' => $values['primary_address_street_postalcode']),
)
);
$entry_id = $prod_register->id;
$relationship_parameters = array(
"module1" => "myco_product_register",
"module1_id" => array($entry_id),
"module2" => "myco_products_versionning",
"module2_id" => array($values['products_versionning'])
);
//Now i'm setting the relationships
$response = $soapClient->set_relationship($sessid, "myco_product_register", $entry_id,
'myco_products_versionning_id_c', $values['products_versionning'], array(), 0);
$response = $soapClient->set_relationship($sessid, "myco_product_register", $entry_id,
'myco_resellers_id_c', $values['reseller'], array(), 0);
Both set_entry requests work and return a working id, but no one of the relationships work ($responses contains a failed equal to 1). So that's not a connection problem or such.
Talking about the relationships, one guy from the devblog said that
there has to be a relationship between the two modules
there has to be at least one related field in the module which handle the relation, whose name you can find in the module's vardefs.php
and i have
A One-to-one relationship between the product_register module and both products_versionning and resellers
A related field in product_register for each related module.
What may i be missing ?
try checking the log file of SugarCRM, you should find some mistakes. I used this API to create a relationship between Contacts and Accounts, and working properly. On the logs might find the answer to the problem.
try {
$result = $this->soapClient->set_relationship($this->sessionId,
$accountModuleName, $accountId, $relationName, $contactsId);
$this->doEvent(self::EVENT_WS_OPERATION_CALL);
if ($result->created > 0 && $result->failed === 0) {
return true;
} else {
return false;
}

Amazon AWS, Creating a name tag for ec2 instance using PHP SDK 2

I'm using the latest version (2) of SDK for php. Below is a snippet of code for assigning a name tag to existing instance:
try {
$result = $ec2->createTags(array(
'Resources' => array($instanceid),
'Tags' => array(
'Name' => 'PWC_cwc'),
));
} catch (Exception $e) {
die("Failed to create tag name: ".$e."<br>");
}
Output:
Failed to create tag name: exception 'Guzzle\Service\Exception\ValidationException' with message 'Validation errors: [Tags][Name][Tag] must be of type object' in /Users/harry/Documents/workspace/BigData/vendor/guzzle/guzzle/src/Guzzle/Service/Command/AbstractCommand.php:394 Stack trace: #0
I'm guessing something is wrong with the way I pass the argument, but just couldn't figure out the correct way of doing this
The API link for createTags method is here: http://docs.aws.amazon.com/aws-sdk-php-2/latest/class-Aws.Ec2.Ec2Client.html#_createTags
You have to specify the 'Key' and 'Value' of each tag.
$args = array(
'DryRun' => False,
'Resources' => array($resource),
'Tags' => array(
array(
'Key' => 'firstkey',
'Value' => $firstkeyvalue),
array(
'Key' => 'secondkey',
'Value' => $secondkeyvalue),
array(
'Key' => 'thirdkey',
'Value' => $thirdkeyvalue)
));
$response = $ec2->createTags($args);
Try this:
$result = $ec2->createTags(array(
'Resources' => array($instanceid),
'Tags' => array(
'Tag' => array(
'Key' => '<key>',
'Value' => '<value>'
)
)
));
You need to have an array of 'Tag' inside the 'Tags' array.

How to encode PHP object to nuSOAP response?

I'm building a simple WebService. I have a User PHP class and a webmethod getUser to retrieve a user's information.
I've declared a complexType and everything seems to work perfectly.
$server->wsdl->addComplexType('User',
'complexType','struct', 'all', '',
array( 'id' => array('name' => 'id', 'type' => 'xsd:int'),
'username' => array('name' => 'username','type' => 'xsd:string'),
'password' => array('name' => 'password','type' => 'xsd:string'),
'email' => array('name' => 'email','type' => 'xsd:string'),
'authority' => array('name' => 'authority','type' => 'xsd:int'),
'isActive' => array('name' => 'isActive','type' => 'xsd:int'),
'area' => array('name' => 'area','type' => 'xsd:string')
)
);
$server->register('ws_getUser',
array('user_id' => 'xsd:integer'),
array('user' => 'tns:User'),
$namespace,
"$namespace#ws_getUser",
'rpc',
'encoded',
'Retorna un usuario'
);
function ws_getUser($user_id){
return new soapval('return', 'tns:User', getUser($user_id));
}
However, on the getUser function I'm retrieving the user info as an assoc. array, not the User Object itself.
What I would like to do on getUser is to return a User instance instead, and have nuSOAP serialize it for me. Is this possible?
Edit: I've tried returning a new User() for testing purposes, but the response is
<user xsi:type="tns:User"/>
Guess I've found out an answer that may apply to this case here: http://www.php.net/manual/en/class.soapserver.php
If you want to return a custom object
array from a nusoap webservice, you
have to cast the objects to arrays
like so:
<?php
$users = array();
while($res = $db_obj->fetch_row())
{
$user = new user();
$user->Id = $res['id'];
$user->Username = $res['username'];
$user->Email = $res['email'];
$users[] = (array) $user;
}
return ($users);

Categories