Two Easy PHP SOAP setHeaders Questions - php

Here's the code I'm using to generate the request headers:
$headers = array(
new SOAPHEADER($this->_ns,'username',$this->_username,false, $this->_actor),
new SOAPHEADER($this->_ns,'password',$this->_password,false, $this->_actor));
$this->_client->__setSOAPHeaders($headers);
This generates:
<SOAP-ENV:Header>
<ns2:username SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next">test</ns2:username>
<ns2:password SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next">test</ns2:password>
</SOAP-ENV:Header>
That's all fine and dandy.
Here are my two questions:
The API doc requires that username be ns1:username and password be ns2:password. Mine are both ns2. First of all, what is the significance of the ns1|2? How can I fix this?
Second question is just is there a way to generate the same result by only calling SOAPHEADER() once?

Not easy to say whether the namespace makes a difference without seeing the declaration & knowing the service, but usually the receiving service looks only for the tags in that particular namespace. As you add $this->_ns to both of them, of course they'll be the same. You'll have to provide the proper namespace yourself (prefix doesn't matter, uri does).
Why would you want only 1 call?

Related

XML tags match but namespaces differ

I am trying to setup a Soap connection between a server in php and a client in C. My server is using a working wsdl file and a class to add these methods. I can confirm with Wireshark that my client request is well received and correctly processed.
My issue is that the values of the XML element sent by the server cannot be read because the namespaces differs. By adding debug log in my client I have found that the error is :
Tags 'state' and 'ns2:state' match but namespaces differ
Issue :
The issue seems to be that the server response does not contain any default namespace :
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://www.w3.org/2005/08/adressing"
xmlns:ns2="http://www.namespace1/">
<env:Body>
<ns2:HelloResponse>
<state>OK</state>
<intElement>123</intElement>
</ns2:HelloResponse>
</env:Body>
</env:Envelope>
It looks like <state> and <intElement> are not in any namespace, so it can't match one of the client. In my Wsdl file, these element belongs to xmlns:s="http://www.w3.org/2001/XMLSchema"
What I tried :
Obvious solution is to add an namespace to these element, but I can't find a way to do it.
In my php server, I can modify any request that comes in but can't affect any response that comes out (or at least i didn't find how to do it).
2nd solution : Adding the namespace that describe these element to the Namespace struct in my client and then use the set_namespace() function.
But I couldn't manage to put them to work, please keep in mind that I am still new to the XML/Soap world, any help is appreciated.
As said before, the solution was to add the corresponding namespace to these element.
I managed to do it using ob_get_contents() and adding the namespace to <ns2:HelloResponse>. Using Wireshark was really useful for this kind of stuff.

PHP: How to do I post xml arguments to api?

I have to post to url : https://rightsignature.com/api/templates.xml
One of the arguments is merge_fields and the description is:
Specify the name and email of the roles returned from the prepackageTemplate call. Roles can be references by or by in the form of XML node attributes 'merge_field_name' or 'merge_field_id'. If specified by name (the easiest method), all merge fields with the name specified will take on the value specified. Optional node specifying whether to "lock" the value from the sender is availbed via .
This is what the post xml should look look like:
<merge_fields>
<merge_field merge_field_id="a_233_f309f82jklnm_232">
<value>$100 per hour</value>
<locked>true</locked>
</merge_field>
<merge_field merge_field_name="Employee Name">
<value>J. Employee</value>
</merge_field>
</merge_fields>
This is what xml response looks like:
<merge-fields>
<merge-field>
<page>1</page>
<name>Company Name</name>
<id>a_966_8bffa095998e41ecbdfb624b2fd_5671</id>
</merge-field>
</merge-fields>
Am I suppose to set it to an array like this? :
$arr= array('merge_fields'=>
array('merge_field_email'=>xxx#mail.com),
"another_field"=>"another_value")
)
https://rightsignature.com/api/templates.xml? . $arr
"Well, basically 'it's still AJAX,'" with the encoding being XML not JSON.
You would simply use appropriate XML-manipulation primitives to build and un-build your messages, as discussed here: http://php.net/manual/en/book.xml.php.
It is also possible that the API is what's called SOAP. as discussed here: http://php.net/manual/en/book.soap.php. Or, it might be XML-RPC ("XML remote procedure calls"), as discussed here: http://php.net/manual/en/book.xmlrpc.php.
All three of these pages refer to many other pages with related topics that will be highly-relevant to what you are now trying to do.
It's important that you carefully identify the exact "flavor" of API that you are dealing with, so as to use the most-powerful available libraries of existing code to deal with it at the highest possible level of abstraction. Also, do on-line research (e.g. at GitHub) to see if you can find any existing source-code that already references this API or something very-similar to it. ("Do not do a thing already done.")
The good news is, you know that you're embarking upon "a very, very familiar task" that is well-supported in PHP. And so, to borrow a Perl by-line: "there's more than one way to do it." Search for the most efficient way.

How to create Domain on Jasper via PHP Client

My problem is:
i've got the PHP Client http://community.jaspersoft.com/wiki/php-client-sample-code#About_the_Class from the Jasper Community.
I want to add a Domain with PHP to the Jasper Repository and i've got the needed data in an .xml, like label etc.
In this PHP Client i have to use the class SemanticLayerDataSource to create a domain.
This class got a public variable schema.
But i can't find what this schema needs to work and add an correct domain to repository. There is not info neither on the webside nor in the class.
$semLayer = new SemanticLayerDataSource();
$semLayer->schema = ?????
$semLayer->label = (string)$xml->label; //SimpleXml
.
.
.
Which Data needs schema? An array, a resource or something else? Thank you.
Also a code sample with PHP Client would be really good, cause the documentation is not that good in this point.
Edit: I tried to create a xml as a local file a set for schema the uri of this xml. To create the xml i used this: http://community.jaspersoft.com/wiki/php-client-sample-code#Creating_Binary_Resources
I am able to create a domain, but AdHoc views on this domain doesn't work. I get a null exception from jasper.
According to the REST API docs you need to provide a schema ressource:
<schemaFileReference>
<uri>{schemaFileResourceUri}</uri>
</schemaFileReference>
This ressource represents the whole structure, as written in the domain metadata service description (under the paragraph Working with Domain Schemas):
The v2/domains/metadata service returns only the display information about a Domain, not its internal definition. The fields, joins, filters, and calculated fields that define the internal structure of a Domain make up the Domain design. The XML representation of a Domain design is called the Domain schema.
Currently, there is no REST service to interact with Domain schemas, but you can use the v2/resources service to retrieve the raw schema. First, retrieve the resource descriptor for the Domain. For example, to view the descriptor for the Supermart Domain, use the following request (when logged in as jasperadmin):
GET http://<host>:<port>/jasperserver-pro/rest_v2/resources/Domains/supermartDomain
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<semanticLayerDataSource>
<creationDate>2013-10-10 15:30:31</creationDate>
<description>Comprehensive example of Domain (pre-joined table sets for complex reporting, custom query based dataset, column and row security, I18n bundles)</description>
<label>Supermart Domain</label>
<permissionMask>1</permissionMask>
<updateDate>2013-10-10 15:30:31</updateDate>
<uri>/organizations/organization_1/Domains/supermartDomain</uri>
<version>1</version>
<dataSourceReference>
<uri>/organizations/organization_1/analysis/datasources/FoodmartDataSourceJNDI</uri>
</dataSourceReference>
<bundles>
<bundle>
<fileReference><uri>/organizations/organization_1/Domains/supermartDomain_files/supermart_domain.properties</uri></fileReference>
<locale></locale>
</bundle>
(snip) [...]
The Domain schema is an XML file with a structure explained in the JasperReports Server User Guide. If you wish to modify the schema programmatically, you must write your own parser to access its fields and definitions. You can then replace the schema file in the Domain with one of the file updating methods described in .
Well, i found the solution.
If you want to create a schema per php client, create a new file object.
$file = new \Jaspersoft\Dto\Resource\File();
$file->type = "xml";
$file->label = "MyDomain_schema";
$file->content = base64_encode((string)$schemaXML);
The file content is the base64 encoded (valid) domain schema.
Now set $semLayer->schema = $file. This way works rather good.
Also, there is a way to create the domain via multipart request, but this way is rather complicated with php client. There is a function multipartrequest in the PHP Client, but it seems that this function consists of legacy code.

Posting Data to REST API using JSON and PHP

I've been looking around at similar topics on REST APIs but I am still having some confusion in my project, mostly with the PHP side of things.
USPS provides a REST API with functions that can be called via URL like this: https://epfws.usps.gov/ws/resources/epf/login
To make any call successfully, I have been told that a JSON object must be created and passed as a "POST parameter" with the expected values.
This is the JSON object that needs to be passed in this case:
obj=
{
"login":"loginExample",
"pword":"passwordExample"
}
I have also been given a PHP class that is supposed to manage these calls. This is the login function:
public function login ()
{
// Set up the parameters for a login attempt
$jsonData = array(
'login' => $this->loginUser,
'pword' => $this->loginPass,
);
// Make a login request
$jsonResponse = $this->pullResource
('/epf/login', 'POST', $jsonData);
return $jsonResponse;
}
So I have a few questions regarding this:
The document they sent says
"To make the request calls, a JSON object will need to be created and passed as a POST form parameter obj={jsonObject} for security reasons using content-type “application/x-www-form-urlencoded”."
I know that the login function contains the correct input values that USPS' REST API is wanting, but I'm not sure how to pass them as "obj", or how to apply the "content-type".
I have a "constant" defined at the top of my PHP script that looks like this:
const EPF_BASE_URL = 'https://epfws.usps.gov/ws/resources';
And I noticed in the actual functions that this part of the link is left out and they simply reference '/epf/login' as you can see above. Since "$this" contains lots of different values I'm wondering how it supposedly finds EPF_BASE_URL as needed. Is it similar to how 'using' directives work in C#?
What is the easiest way to call this function and display the result? This is my biggest question. Would I use a separate PHP class with an HTML form? I understand the concept of what it should do but I'm completely lost setting up a development environment for it.
I've been trying all of this with MAMP but would love to know if I'm on the right track or not.
That really depends on their API. Hopefully you get a string back that can be decoded to a JSON object (http://au.php.net/manual/en/function.json-decode.php). Some API might give a simple string that says 'SUCCESS' or 'FAIL'. You've got the code, so take a look at what $this->pullResponse() gives you.
If you've been given a PHP class that is supposed to support the API (hopefully from USPS), then it should already take care of putting the data in the form content, and ensuring is it submitted with the appropriate content-type.
A PHP const is more like a C# static string. It is very likely that the library will use the constant to create the end URL (i.e. EPF_BASE_URL . $resource). If you needed to run against a sand box environment, you could change that constant without having to change all the other code.
That's a very big question, because it depends on how you are programming your application. Procedural, MVC, existing frameworks, etc.
At the very least, you would set the loginUser and loginPass on the instantiated object, and call the login method`. You could then inspect the results, assuming the result is a JSON object, or use your favourite debugging method to see the contents.
I'm having a guess as the USPS API class name.
$uspsApi = new UspsApi();
$uspsApi->loginUser = 'username';
$uspsApi->loginPass = 'password';
$result = $uspsApi->login();
echo print_r($result, true);

Process SOAP Headers in PHP

I am building (in PHP) a SOAP server that is configured by its WSDL to accept messages that look like this:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="https://my.awesome.namespace/">
<SOAP-ENV:Header>
<ns1:Header>
<ns1:APIKey>E4C5BDE0-48DC-543C-1CA3-8E55C63F8E60</ns1:APIKey>
<ns1:SiteID>111</ns1:SiteID>
</ns1:Header>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:Heartbeat>
<ns1:Message>Hello world.</ns1:Message>
</ns1:Heartbeat>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I had no problem getting my SOAPServer to process Heartbeat messages - $server->addFunction("Heartbeat"); works fine. I want, however, to be able to process the contents of the <ns1:Header> enclosure - so I can validate the API key and Site ID to make sure they are what they should be.
I looked here, (and of course elsewhere) but the responder seems to have missed the point of the question. Does anyone know how I can access the header element to validate? Do I add a function for Header the way I would a method in the body? ($server->addFunction("Header");?)
Thanks very much in advance.
Found it! Here's what you do.
Create your SOAP server:
$server = new SoapServer($your_wsdl,$any_options);
$server->setClass($name_of_your_class);
$server->handle($location_of_request_data);
The class named in $name_of_your_class, in addition to containing functions for each service defined in $your_wsdl, should also contain a function named for whatever you have in your <SOAP-ENV:Header> tag enclosure. I have <ns1:Header>, so my function is named Header. Put whatever logic you need in there. For me, I wanted to validate the API key and site ID, so I created a private variable, and if the API key and site ID are correct, the variable is set to true. All of the other functions in the class check to see if that variable is true before proceeding, and if not, a SOAPFault is thrown.
Hope this helps anyone who comes across this question on Google.
P.S.: For the functions in the class defined in $server->setClass(), don't forget that they must accept arguments in the order defined in the WSDL. That tripped me up.
Good luck to all other PHP/SOAP developers - seems like we all need it.
Edit/P.P.S.: For whatever reason, simply calling $server->addFunction("Header") did not work for me - I tried that first before I tried the setClass approach above. Just a heads-up to folks.

Categories