complete noob, SOAP PHP, request with authentication, store in mySQL - php

OK, so I'm completely lost here! Been staring myself blind at the screen for two days and all the explanations/tutorials I can find on the internet assumes you've already worked with SOAP before.
Using SOAPui I was at least able to try out the request and see the result :) But I need to replicate this in PHP... e.g, make request in PHP using authentication credentials and then store the response in a mySQL table.
This is how the request looks like
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:DoThis>
<tem:licensId>[MYLICENSID]</tem:licensId>
<tem:licenskey>[MYLICENSKEY]</tem:licenskey>
<tem:guid>[AGUID]</tem:guid>
</tem:DoThis>
</soapenv:Body>
</soapenv:Envelope>
So I need to verify/authenticate the request (i guess)? But how do I do this with PHP?
Once I get the request to work, how will the response be presented? I would like to insert it into an existing mySQL DB. That is to say that this is my "end game"/the purpose of this. Retrieving information from external system, compare it to existing information in DB, and if new information exists, replace current or add new.
I tried
$wsdl = 'http://URLTOSERVICE/Export.svc?wsdl';
$client =
new SoapClient(
$wsdl,
array(
"tem:licensid" => "[MYLICENSID]",
"tem:licenskey" => "[MYLICENSKEY]",
"tem:guid" => "[AGUID]"
)
);
print_r($client->DoThis());
But the response is about as interesting as looking in to a blank paper for 2 days... i.e, returns nothing.
Like I said in the topic title and at the beginning. I have no experience with SOAP. So please, if some kind soul out there takes the time to answer, keep in mind that I need clear and precise explanations :)
And thank you to anyone taking the time to help me understanding this...

can you indicate the WSDL url? I would suggest you to try a WSDL to php converter to see more clearly how to call the SOAP Web service.
To set credentials as the request you indicate, you must use the Soapheader class, http://php.net/manual/fr/class.soapheader.php, and call the __setSoapheaders, http://www.php.net/manual/fr/soapclient.setsoapHeaders.php, before calling the operation.
Let me know if you need any help or a WSDL to php converter.

Related

REST (PHP, CURL) PUT/POST XML Issue: 400 Bad Request, "Invalid URL" Response with Walmart OAuth API (Postman to test)

There's a lot to unpack here. First of all, I've edited the title because I realize while eventually my REST request will be implemented into PHP code, right now I've stripped this down to Postman to test JUST the REST, so I've stripped it as low and basic as possible. I can officially say the problem is with my request.
Basically, I'm making a POST request and also testing with a PUT request to Walmart's API using the "new" OAuth authentication. Sounds grand. GET works BEAUTIFULLY in Postman and in my actual PHP code. POST and PUT immediately return the exact same error, no matter what and how I do: 400 Bad Request, Invalid URL. In the case of my PUT test, which I was doing because it's a simpler and faster text with far less XML to try to comb through, here's the exact response in HTML headers:
<HTML>
<HEAD>
<TITLE>Invalid URL</TITLE>
</HEAD>
<BODY>
<H1>Invalid URL</H1>
The requested URL "http://%5bNo%20Host%5d/v3/inventory?", is invalid.
<p>
Reference #9.c9384317.1556319123.8c89b8dc
</BODY>
</HTML>
I have left testing in PHP through my server and moved into Postman to try to locate the exact issue I'm having, and GET requests work beautifully. I am generating a new Token every 15 minutes or so. I have done... SO many minor changes, but the way the Feed examples and requests work, for all that I can tell I'm doing everything right. I honestly think I'm losing my marbles at this point.
What is most frustrating to me is that GET works. My TOKEN is working. My OAuth is working just fine. A lot of the headers that GET uses for the Walmart API are the exact same between PUT/POST/GET. The difference here is ONLY that the link has query parameters AND XML being shoved into the body. Edit: What I mean is that my headers do not change between the GET and the POST; the only thing that changes in what I am supplying is that XML is being sent in the body, and that query params are required. This is the only thing that changes between a successful GET and an unsuccessful 400 bad request PUT/POST. This leads me to believe something is wrong with how I'm processing the query params or my XML, but considering in the below example I've copy/pasted the XML... I'm not sure. It is an existing item in our catalog, I know for a fact.
Something I have noticed that I'm not quite knowledgeable enough to know if it's an issue or not with Postman is that Walmart's API requests that content-type be multipart/form-data. I've noticed it uses the term "example" when stating this, however, it usually says "this or this" if it'll accept something else. If I switch content-type in Postman to multipart/form-data, however, the Body automatically becomes raw: text instead of raw: XML(application/xml) or text/xml. If I try to swap the raw to those types, it flips my content-type automatically to application/xml, so that's a little... hinky.
I am not going through a Proxy. I've turned off Global Proxy Configuration and Use System Proxy. Request timeout is set to 0. There's nothing Client Certificates. I mean, GET works, and my Token is successfully generated via outside PHP code (not in Postman, couldn't get that to work, said heck it).
HEADERS
PUT URL: https://marketplace.walmartapis.com/v3/inventory?sku=0xyz0
AUTHORIZATION
Bearer Token: Bearer Basic --insert token here--
WM_SVC.NAME: Walmart Marketplace
WM_QOS.CORRELATION_ID: randomString123
WM_SEC.ACCESS_TOKEN: --insert token here--
Accept: application/xml
Host: https://marketplace.walmartapis.com
Content-type: multipart/form-data
BODY
raw: XML(application/xml)
<?xml version="1.0" encoding="UTF-8"?>
<inventory xmlns="http://walmart.com/">
<sku>0xyz0</sku>
<quantity>
<unit>EACH</unit>
<amount>7</amount>
</quantity>
<fulfillmentLagTime>1</fulfillmentLagTime>
</inventory>
Exact response
400 Bad Request
<HTML>
<HEAD>
<TITLE>Invalid URL</TITLE>
</HEAD>
<BODY>
<H1>Invalid URL</H1>
The requested URL "http://%5bNo%20Host%5d/v3/inventory?", is invalid.
<p>
Reference #9.c9384317.1556320429.8ca752c4
</BODY>
</HTML>
Please send help, I think I've been staring at this so long I'm going to leave this physical world behind. Walmart relatively recently updated their authentication to OAuth and they've made vague passes at saying their old authentication will be deprecated and phased out, so I obviously want to try to get this to work.I tried to copy paste everything as best as possible. That XML is copy-pasted almost letter for letter from their example, with my own product switched in.
Also, the reference number down there always changes every time I run this, so it's not something I can actually look up. I've only supplied the Postman side of things because frankly if I can get that to work, my PHP will be fine, I've already knocked out some minor issues with the successful GET request.
If it's a semi-colon issue, I'll scream.
API Documentation: https://developer.walmart.com/#/apicenter/marketPlace/latest#updateInventoryForAnItem
Well, I've figured it out.
You'll notice I'm required to supply a "Host" with my headers. That host is replacing my URl that I'm trying to connect to via POST/PUT/GET, so if my Host is https://marketplace.walmartapis.com, then my request URL is https://https://marketplace.walmartapis.com.
Once I took the https:// out of the host, the entire thing granted me a 200 response. The times I got a correct GET response, I had actually copy-pasted the correct HOST without the HTTPS by pure chance, so I completely missed this between my two separate test cases.

Invoking WCF service with PHP (with federated security)

I’m trying to invoke a WCF service (.NET) from PHP. It’s a little more complicated than just using a SoapClient since the service uses a WS2007FederationHttpBinding to authenticate.
Here’s the code I’m using at the moment. I haven’t even added credentials as I’m not sure how, but regardless, I’m not even at the point where I’m getting access denied errors.
$wsdl = "https://slc.centershift.com/sandbox40/StoreService.svc?wsdl";
$client = new SoapClient($wsdl,array(
//'soap_version'=>SOAP_1_2 // default 1.1, but this gives 'Uncaught SoapFault exception: [HTTP] Error Fetching http headers'
));
$params = array();
$params['SiteID'] = 123;
$params['GetPromoData'] = false;
$ret = $client->GetSiteUnitData(array('GetSiteUnitData_Request'=>$params));
print_r($ret);
Which WSDL should I be pointing to?
https://slc.centershift.com/Sandbox40/StoreService.svc?wsdl
Seems to be very short, but includes a reference to (note the wsdl0) https://slc.centershift.com/Sandbox40/StoreService.svc?wsdl=wsdl0
https://slc.centershift.com/Sandbox40/StoreService.svc?singleWsdl
Seems to have everything in it.
Do I need to specify SOAP 1.2? When I do, I get a connection timeout ([HTTP] Error Fetching http headers). When I don’t, the default of SOAP 1.1 is used and I get a [HTTP] Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'. Is this because I’m not authenticated yet, or because I’m using the wrong SOAP version?
How to authenticate in PHP? Here’s the corresponding .NET/C# code. Do I need to somehow put these as SOAP headers? Or am I thinking about it all wrong, and I need to do some kind of authentication before I even call the method (from what I read, I’m supposed to get a token back and then use it for all future method calls – I think I see an example of this in an answer here on Stack Overflow.
If I call $client->__getFunctions(), using either WSDL and either SOAP version, I’m getting a valid list of all functions, so I assume either of these is fine and my real issue is the authentication.
Other programmers I’ve talked to had spent time trying to get this to work, but gave up and instead implemented a proxy in .NET. They pass their parameters from PHP to their own unsecured .NET service, which in turn calls this secure service. It works, but seems crazily inefficient to me, and counter-productive, as the purpose of WCF is to support all types of clients (even non-HTTP ones!).
I’ve read How to: Create a WSFederationHttpBinding on MSDN, but it didn’t help.
You can use this URL for WSDL https://slc.centershift.com/Sandbox40/StoreService.svc?singleWsdl. This WSDL has all definitions.
You have to use 1.2 because this webservice works with SOAP 1.2 version. I tried it with 1.1 and 1.2 and both of them gived error. 1.1 is version error, 1.2 is timeout error. I think there is an error at this test server. I used it with svcutil to generate code but it gived error too. Normaly it should get information and generate the code example to call service.
Normally you can add authenticate parameters with SoapHeader or directly add to options in SoapClient consruct (if service authentication is basic authentication). I write below code according to your screenshot. But it gives timeout after long wait.
$wsdl = "https://slc.centershift.com/sandbox40/StoreService.svc?wsdl";
$client = new SoapClient($wsdl,array('trace' => 1,'soap_version' => SOAP_1_2));
$security = array(
'UserName' => array(
'UserName'=>'TestUser',
'Password'=>'TestPassword',
'SupportInteractive'=>false
)
);
$header = new SoapHeader('ChannelFactory','Credentials',$security, false);
$client->__setSoapHeaders($header);
$params = array();
$params['SiteID'] = 100000000;
$params['Channel'] = 999;
try {
$ret = $client->GetSiteUnitData($params);
print_r($ret);
}catch(Exception $e){
echo $e->getMessage();
}
__getFunctions works, because it prints functions defined in WSDL. There is no problem with getting WSDL information at first call. But real problem is communication. PHP gets WSDL, generates required SOAP request then sends to server, but server is not responding correctly. SOAP server always gives a response even if parameters or request body are not correct.
You should communicate with service provider, I think they can give clear answer to your questions.
Having worked with consuming .NET WS from PHP before I believe you would need to create objects from classes in PHP that matches the names that .NET is expecting. The WSDL should tell you the types it is expecting. I hope this assist with your path forward!
If the SOAP call works from a C# application, you could use Wireshark (with the filter ip.dst == 204.246.130.80) to view the actual request being made and then construct a similar request from php.
Check this answer to see how you can do a custom SOAP call.
There's also the option of doing raw curl requests, since it might be easier to build your xml body, but then you would have to parse the response yourself with simplexml.

Netsuite error :You are not requesting the correct data center for your company"

I using Netsuite PHPToolkit version 2014_1.
$nsendpoint = "2014_1";
$nshost = "https://webservices.netsuite.com";
Today I received this error when login via webservice
You are not requesting the correct data center for your company ! Please correct the host in the URL.
This is my response
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<soapenv:Fault>
<faultcode>
soapenv:Server.userException
</faultcode>
<faultstring>
You are not requesting the correct data center for your company ! Please correct the host in the URL.
</faultstring>
<detail>
<platformFaults:unexpectedErrorFault xmlns:platformFaults="urn:faults_2014_1.platform.webservices.netsuite.com">
<platformFaults:code>
USER_ERROR
</platformFaults:code>
<platformFaults:message>
You are not requesting the correct data center for your company ! Please correct the host in the URL.
</platformFaults:message>
</platformFaults:unexpectedErrorFault>
<ns1:hostname xmlns:ns1="http://xml.apache.org/axis/">
partners-java10010.bos.netledger.com
</ns1:hostname>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
It was working well before.
Today the NetSuite Data Center URL is different for each customer.
After configuring NSconfig.php, run the following script to identify the endpoint URL. The example comes from the samples folder of PHPToolkit_2018_2,
require_once 'PHPToolkit/NetSuiteService.php';
$service = new NetSuiteService();
$service->useRequestLevelCredentials(false);
$params = new GetDataCenterUrlsRequest();
$params->account = NS_ACCOUNT;
$response = $service->getDataCenterUrls($params);
$webservicesDomain = $response->getDataCenterUrlsResult->dataCenterUrls->webservicesDomain;
print "url: $webservicesDomain";
Once you have the URL you can then enter that in your configuration.
The answer from #Charlie Dalsass to use getDataCenterUrls is 100% correct if your SuiteTalk client will be accessing multiple NetSuite accounts.
However, if your client will only use one account, you can probably get away with hardcoding the URL
https://1234567.suitetalk.api.netsuite.com
where 1234567 is your account ID. So, an example WSDL URL you'd pass to your SOAP client would be
https://1234567.suitetalk.api.netsuite.com/wsdl/v2018_1_0/netsuite.wsdl
I've come across that error but not in that context.
I have found it whilst working on accounts that have the system.netsuite.com data center specified and sometimes have to switch to system.na1.netsuite.com
I would give na1 a try.
I believe it's related to the 2 data centers across the States, East / West Coast and the way requests are routed.
Endpoint needs to be "https://webservices.na1.netsuite.com" not "https://webservices.netsuite.com", kind of annoying.
I got this error , but for me the mistake was with my account_id I was using, it's case sensitive

Making a SOAP request

I am new to PHP - Started little over a month back with PHP, JS and HTML with a few hours a day.
I have done a lot of homework on this but can't make head and tail out when it comes to implementation. I don't have a hardcore programmer who could sit with me on this, hence here. But I am sure if this question is answered, it would help a lot of newbir and experienced programmers there
The Problem - I can understand the concept of SOAP but cant makout how to make a simple soap request. What would be the steps in PHP.
//php SOAP extention is properly installed
Create a new SOAP client :
$variable = new SoapClient ;
$inputxml = " the input XML file as a string ";
varibale__doRequest($input xml, "string location -??
I have the XML input as a variable.. what location do i specify.. need to enable cache and a cache location ??,...)
Thats the php function i am trying to use - how to use this http://www.php.net/manual/en/soapclient.dorequest.php
// PHP code to obtain response as XML
// How to store the reponse in a variable as a string
Can someone demonstrate a simple SOAP request using PHP on a blog.
I couldnt find one example, all focus on creating SOAP services or SOAP servers.. I just wanna create a SOAP client and make a request in PHP - any detailed laymnas guide - PHP specific ??
This is the SOAP service I am struggling with - Find Company by Keyword at
http://developer.dnb.com/service-directory/sales/16682663-1.html
If someone could write a single post blog explaning the details, would be immensely grateful
PS: Not sure if my frustration is justified, but SOAP and REST concepts make programming sound like Rocket Science.. I have spent over a week, 8 hrs a day, dont have a clear idea on making SOAP requests though I have a fair understanding of the SOAP concept. As far as REST goes, it has me super confused - i don wanna touch that thing here at the moment.
There is the php soap client but you dont HAVE to use it..
you can build your request manually and post it with curl, you can then parse the response as you like.
/**
* Request login body
*/
const REQUEST_LOGIN = '<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://www.company.com/soap" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding">
<env:Body>
<ns1:RequestLogin xmlns:ns1="http://www.company.com/soap">
<ns1:Name>%username%</ns1:Name>
<ns1:OrgId>0</ns1:OrgId>
<ns1:AuthType>simple</ns1:AuthType>
</ns1:RequestLogin>
</env:Body>
</env:Envelope>
';
SOAP in PHP is a little easier than it seems. If you are looking for a long form tutorial there is a nice one up on DevZone. I would also keep the SoapClient class documentation handy.
The gist of working with Soap
// $endpoint is the callback/uri of the WSDL.
// $options is an array of options.
$client = new SoapClient($endpoint, $options);
You can learn more about he options and endpoint in the details for the constructor.
PHP has some magic methods and __call is one of them. The easiest way to use SOAP is often to just call an available method. For example:
$response = $client->getLoginToken(array(
'siteid' => 'foo',
'secid' => 'bar',
));
In this case getLoginToken is a SOAP method call. The SOAP client sees that it's not a method on the object and passes that as the method on to SOAP. The array passed in is arguments to pass on to the SOAP endpoint as arguments.
I would also checkout the examples on the soapCall page. Best of luck.

how to return custom types with php soap server?

I'm in with PHP SoapServer working in non-wsdl mode. I have the server set up to handle the data and return a response using setClass(). I tried returning an associative array, but that translates into SOAP maps with items, keys and values. I'd like to respond with the following:
<soap:Body>
<AsyncResponseOperationResponse xmlns="http://www.sample.com/">
<AsyncResponseOperationResult>
<Succeeded>true</Succeeded>
<Comments>
The operation was a success
</Comments>
</AsyncResponseOperationResult>
</AsyncResponseOperationResponse>
</soap:Body>
The variables would be whether success is true or false, and the comments.
I've been trying to read about the 'typemap' option, but it is not very well documented, and what I've found so far has only confused me further. The resources I've found so far are the php unit tests, like this one and this one, as well as this stackoverflow question
Can anyone provide me an example that does what I'm trying to do? I think I would be alright switching to wsdl mode with autodiscover (using Zend's Soap Server), if that comes up as a solution.
Edit:Until I figure out how to do it the right way, I'm just writing out all the XML manually.
header("Content-type: text/xml");
echo "<?xml version="1.0" encoding="utf-8"?><soap:Envelope ...

Categories