PHP/SOAP - How to create working request with SOAP - php

Here is my request in SoapUI:
With SoapUI i send the request and i receive good response.
Here is my PHP code so far:
<?PHP
$wsdl = 'https://onlinefatura.xyz/foyws/FoyOnlineApiGateWS.asmx';
try{
$clinet=new SoapClient($wsdl);
$ver =array(
"UserName"=>"USERNAME",
"Password"=>"PASSWORD",
"ApiKey"=>"APIKEYHERE",
"Date"=>"2017-11-09",
);
$quates=$clinet->GetAddedBalanceList($ver);
var_dump($quates);
}
catch(SoapFault $e)
{
echo $e->getMessage();
}
When i execute the code i receive:
SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://onlinefatura.xyz/foyws/FoyOnlineApiGateWS.asmx' : Premature end of data in tag html line 3
Somehow i'm doing something wrong. I'm not really sure if i made my PHP request correct.
Where is my mistake, and how the correct request should look like ?

With an SoapClient error like "Premature end of data in tag html" your link to the WSDL file is usually not correct.
Try this one: https://onlinefatura.xyz/foyws/FoyOnlineApiGateWS.asmx?WSDL

Related

SoapClient call returns 500 Internal Server Error

I am trying to connect to an API using PHP and its built-in SoapClient. I have checked against the url I was given through the ill-formatted documents the client gave and $client->__getFunctions() returns a list of three functions. HelloWorld($name), which responds with Hello ~name~, shows me that I am communicating with the server through the SoapClient call and the URL is correct.
However, when I try to access one of the other methods that __getFunctions() gives me, even after copy/pasting the XML from the docs and putting in my own credentials, I am still being given an Internal Server Error faultstring and 500 as faultcode from the SoapFault object.
I am sure that it is my own XML string that is causing the issue but I cannot for the life of me figure out how. Reaching out to the API provider directly hasn't proven helpful. This is my first time dealing with Soap/Web Services so I am unsure of where to go from here.
I did wget http//xxx.xxx.xxx?wsdl and it returned me what looks like a valid XML response, the same one I get when I go directly to the url in the browser. What should I be looking into in order to solve this issue? All of the past API's I've dealt with have been JSON/RESTful so I feel out of my element trying to debug PHP errors.
Edit
I have slowly deleted parts of my method call and parts of my XML string, trying to trigger a different error or something in order to find what I need to fix. What I have found is that by not passing in my XML string, I get a valid response from the $client->FunctionCall(...). It's an "this isn't right" message but it's a message! In fact, passing that function ANYTHING for the xml parameter causes the 500 http faultcode/faultstring. Does this mean that my XMl is poorly formatted or does it mean that there is an issue on their end handling requests?
Second Edit
If I make my $client decleration as follows, I get the faultstring Could not connect to host
$opts = array(
'ssl' => array('ciphers'=>'RC4-SHA')
);
$client = new SoapClient($CREDS['orderingWSDL'], array (
"encoding"=>"ISO-8859-1",
'stream_context' => stream_context_create($opts),
'exceptions'=>true,
));
I am getting more confused the longer I try to fix this.
Sometimes a 500 status coming from a SOAP service could be a SoapFault exception being thrown. To help your troubleshooting, you'll want to be able to inspect both your request XML, and the response XML.
Put your code in try/catch blocks, and use $client->__getLastRequest() and $client->__getLastResponse() to inspect the actual XML.
Example:
$client = new SoapClient('http//xxx.xxx.xxx?wsdl', array('soap_version'=>SOAP_1_1,'trace' => 1,'exceptions' => true));
try {
$response = $client->someFunction();
var_dump($response);
} catch (Exception $e) {
var_dump($e->getMessage());
var_dump($client->__getLastRequest());
var_dump($client->__getLastResponse());
}

Parse.com after_save from Webhook produces invalid json

I'm seeing the following error in my Parse.com Error logs:
E2015-09-28T12:40:37.531Z]vWEB after_save triggered for MPPChatRoom for user gI8UxW2JNa:
Input: {"object":{"counter":0,"createdAt":"2015-09-18T12:35:28.195Z","description":"client at Milton","lastMessage":"VGVzdA==\n","lastUser":{"__type":"Pointer","className":"_User","objectId":"Eoi7gcQ4Rs"},"memberCount":2,"members":["Eoi7gcQ4Rs","gI8UxW2JNa"],"mppfile":{"__type":"Pointer","className":"MPPFile","objectId":"3tZWUNHXlf"},"objectId":"jZS5dhQPna","owner":{"__type":"Pointer","className":"_User","objectId":"Eoi7gcQ4Rs"},"roomId":"88b17cd0-63cd-40c7-8b7a-3b6d356768be","status":1,"title":"Tom Grey","updatedAction":{"__type":"Date","iso":"2015-09-18T12:59:19.995Z"},"updatedAt":"2015-09-28T12:40:37.528Z","user":{"__type":"Pointer","className":"_User","objectId":"gI8UxW2JNa"}}}
Result: Invalid JSON
I'm scratching my head over this as I don't have any custom after_save cloud code functions on that class. I do however have a webhook for the after_save on that class:
Webhook Type: afterSave,
Class: MPPChatRoom,
URL: https:// my domain /messagePush/parseMessagePush.php
As it is an after_save I can't control the input, and looking at the above input, I can't see anything wrong with the JSON either. The json above is valid when I copy and paste it into https://jsonformatter.curiousconcept.com/
Can anyone help?
EDIT 1:
I'm new to webhooks and I'm not a PHP dev so I'm assuming the PHP is producing the error, not Parse? Here is the initial code:
include "../includes/config.inc.php";
$sql_object = new sql_class('parseMessagePush.php');
ob_start();
echo "<pre>";
print_r($_POST);
print_r($_GET);
print_r($_SERVER);
print_r(json_decode(file_get_contents('php://input'), true));
$dataLog = json_decode(file_get_contents('php://input'), true);
I'm now thinking one of those json_decode calls is causing an exception. Though I don't see why Parse would send invalid json.
I think this issue was solved by echoing back JSON success data in the parseMessagePush.php file:
header("Content-Type: application/json");
$sucessData = array('status_code' => '200',"status_message" =>'success');
echo json_encode($sucessData);

How to keep LineFeed in GuzzleHttp Response Body

I am doing and cUrl request using Guzzle.
$client = new GuzzleHttp\Client();
try {
$response = $client->get($url);
} catch (\GuzzleHttp\Exception\RequestException $ex) {
// handle error.
}
The server response is formatted like this:
"field1","field2","field3"\n
"value1","value2","value3"\n
"value4","","value5"\n
Using GuzzleHttp\Client, I receive the following response body
"field1","field2","field3""value1","value2","value3""value4","","value5"\n
Is it possible to set the Guzzle Client not to replace line feed chars in the response body?
We don't know what your response looks like.
We don't know how you are viewing the response.
In the presence of these two details I would have to guess that you might have to implement some type of stream decorator so that only single lines of the response are read in at a time.

PHP SoapServer addSoapHeader ignored with SoapFault

I have written a PHP SOAP Service that accepts Basic Authentication credentials as outlined at http://www.whitemesa.com/soapauth.html. I did this by defining a method BasicAuth inside the handler class of the SOAPServer instance. This all works fine.
However, when authentication fails for some reason (incorrect username, no BasicAuth header in the request) I'd like to include a BasicChallenge header in my response, like this:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<h:BasicChallenge xmlns:h="http://soap-authentication.org/basic/2001/10/"
SOAP-ENV:mustUnderstand="1">
<Realm>Realm</Realm>
</h:BasicChallenge>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>Authentication failed</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The following code does not work (the header is not added to the response).
$soapServer->addSoapHeader(new SoapHeader("http://soap-authentication.org/basic/2001/10/", "BasicChallenge", array("Realm" => "Realm"), true));
throw new SoapFault("Client", "Authentication Failed");
Calling $soapServer->fault() instead of throw new SoapFault does not make a difference.
I've tried constructing the Fault object myself, and returning that as a regular response, but I was unable to get PHP to send a well-formed response.
Thanks in advance.
This was 2013 and I actually have exactly the same problem. Well, it 's 2019 and PHP 's current version is 7.3 and 7.4 is coming up to us with big steps. Unfortunately the SoapServer class ignores soap headers completely in a SoapFault case.
I 've written a small workaround to manipulate the XML response of the soap server. For everone who 's having the same issue, here 's a small example, how to solve it.
1. Initialise your Soap Server
$server = new SoapServer($wsdl, $options);
ob_start();
$server->setObject($service);
$server->handle();
$response = ob_get_contents();
ob_end_clean();
Actually we 're doing a simple initialization. Instead of simple returning the content we intercept the xml response with the output buffering functions. The result of the is a xml string in $response.
2. Find out if the reponse is a fault
Actually the SoapServer class is adding soap headers, if it was a valid response. We have to find out, if the response is a fault.
$doc = new DOMDocument();
$doc->loadXML($response);
$xpath = new DOMXPath($doc);
$isFault = $xpath->query('//*[local-name()="Fault"]')->length;
Just load the response xml string into the DOMDocument class. From now on we are able to access xml elements with DOM functions. For better handling I 'm using the DOMXPath class. Of course it is also possible to determine the XML nodes with the DOMDocument class. The $isFault variable is useful for the next step.
3. In fault case set a soap header
Unfortunately there is no fancy addSoapHeader function for simply setting a soap header. We have to do it manually in this case.
if ($isFault) {
$header = $doc->createElementNS('http://schemas.xmlsoap.org/soap/envelope/', 'Header');
$body = $doc->getElementsByTagNameNS('http://schemas.xmlsoap.org/soap/envelope/', 'Body')->item(0);
$realm = $doc->createElementNS('http://soap-authentication.org/basic/2001/10/', 'h:Realm');
$basicChallenge = $doc->createElementNS('http://soap-authentication.org/basic/2001/10/', 'h:BasicChallenge');
$basicChallenge->appendChild($realm);
$header->appendChild($basicChallenge);
$doc->documentElement->insertBefore($header, $body);
}
$xmlResponse = $doc->saveXML($doc->documentElement);
header('Content-Length: ' . strlen($xmlResponse));
echo $xmlResponse;
exit();
In a fault case we create a header element and add all the child nodes we need. If averything was appended insert the header before the body, save the new xml structure in a string and echo it.
Hope this helps a bit.

How to get a SOAP post in PHP?

OK n00b here with SOAP,
Would like some clarification on how to use SOAP.
Question:
I have a Java JSP that posts a WSDL (Looks like XML format) to my PHP script, but how do I get this in the PHP script? The URL for the WSDL will be different every time.
I'm sure it's very simple but just don't see how or am I not understanding this correctly?
You can try something like this:
try {
if (!($xml = file_get_contents('php://input'))) {
throw new Exception('Could not read POST data.');
}
} catch (Exception $e) {
print('Did not successfully process HTTP request: '.$e->getMessage());
exit;
}
This will read the body of the POST request to the $xml variable and print an error if there is one.
Do you mean that the JSP sends the WSDL in a POST request to the PHP script?
If so, have a look at the $_POST array. If you specify exactly how the JSP sends it, I can probably help you more.
Anyway, once you have the WSDL url in a variable in your PHP script, you can have at it with the SoapClient class.
Assuming the best scenario:
$soapClient = new SoapClient($wsdlUrl, $soapOptions);
$soapClient->callYourMethod();
But you're likely to hit a lot of brick walls when using SOAP. Here's the documentation for SoapClient.
Edit:
So, the WSDL is POST-ed. Then, you could access it either by using $HTTP_RAW_POST_DATA if the XML string was sent as the HTTP body, or by using the $_FILES superglobal if the XML string was send as a part of a multipart request.
Something like this:
$wsdl = $HTTP_RAW_POST_DATA;
$wsdlUrl = 'data:text/xml;base64,' . base64_encode($wsdl);
$soapClient = new SoapClient($wsdlUrl);
Anyway, $HTTP_RAW_POST_DATA is only available if the php.ini setting always_populate_raw_post_data is turned on. Also, if the request was multipart, this setting is ignored, $HTTP_RAW_POST_DATA is not populated but you get access to the posted parts using $_FILES. And you may, indeed, use php://input instead of $HTTP_RAW_POST_DATA.
Also, data URIs may only be used when allow_url_fopen is turned on in php.ini.

Categories