PHP SoapClient - how to get request to server and response - php

I try to create script for communication with WS-Security (for the first time) in PHP:
require ('WSSoapClient.php');
$soapclient = new WSSoapClient('https://katastr.cuzk.cz/trial/dokumentace/ws22/wsdp/vyhledat_v22.wsdl');
$soapclient->__setUsernameToken('username', 'password');
$params = array('katastrUzemiKod'=>693936, 'kmenoveCislo'=>1385);
$response = $soapclient->__soapCall('najdiParcelu', $params);
var_dump($response);
And this script failed:
PHP Fatal error: Uncaught SoapFault exception: [wsse:InvalidSecurity]
Error on verifying message against security policy Error code:1000 in
/home/jura/bin/WSSoapClient.php:75
Is any way to see, what this script exactly sent to server and what was the response?

The problem is the $soapclient->__setUsernameToken('username', 'password') function is expecting a 3rd parameter of either 'PasswordDigest' or 'PasswordText'.
This is badly handled in the WSSoapClient class. It should really throw an exception if the passwordType argument is missing. What it tries to do is this:
// $this->generateWSSecurityHeader() returns an empty string if 3rd parameter missing.
$this->__setSoapHeaders($this->generateWSSecurityHeader());
If PHP is in strict mode like mine you would get these warnings:
PHP Warning: SoapClient::__setSoapHeaders(): Invalid SOAP header...
Warning: SoapClient::__setSoapHeaders(): Invalid SOAP header...
You need to figure out the password type and pass that as your 3rd argument in the setUsernameToken() function.

Related

Invalid SOAP message or SOAP version mismatch - maybe due to xop:Include?

I used Wireshark to capture what my browser was sending to a printer and captured this:
https://pastebin.com/ZgpDVazX
I'm trying to duplicate that in PHP with the SOAP extension and am having some difficulty. Here's my PHP code:
<?php
$client = new SoapClient(dirname(__FILE__) . '/WebPackage/WSDPrinterService.wsdl', ['trace' => 1]);
$client->__setLocation('http://192.168.1.116/WebServices/PrinterService');
$temp = new stdClass();
$temp->DocumentId = 1;
$temp->Compression = 'none';
$temp->Format = 'unknown';
$params = new stdClass();
$params->JobId = 1;
$params->DocumentDescription = $temp;
$params->LastDocument = true;
$params->DocumentData = file_get_contents('filename.pdf');
$client->SendDocument($params);
Here's the error I get:
[30-Dec-2021 12:57:15 America/Chicago] PHP Fatal error: Uncaught SoapFault exception: [] in /home/neubert/test.php:16
Stack trace:
#0 /home/neubert/test.php(16): SoapClient->__call('SendDocument', Array)
#1 {main}
thrown in /home/neubert/test.php on line 16
If I put $client->SendDocument($params) in a try / catch block and do $client->__getLastRequest() / $client->__getLastResponse() I can see the request (https://pastebin.com/9mTEBD2y) / response (https://pastebin.com/ue94kQUZ).
The faultcode part of the response says "SOAP-ENV:VersionMismatch" but the faultstring makes it sound like there could be something else wrong with the request other than just the version. None-the-less I tried to change the SOAP version by adding 'soap_version' => SOAP_1_2 (and SOAP_1_1) to the ['trace' => 1] array. With SOAP_1_2 the request (https://pastebin.com/cZGusCXa) / response (https://pastebin.com/PLfTV8qt) changes a bit as does the error (End of file or no input: Operation interrupted or timed out) but it's still not working and the error is still just as cryptic to me.
The only thing I can figure is that the DocumentData isn't being formatted correctly. Here's the DocumentData part of the good SOAP request:
<pri:DocumentData>
<xop:Include href="cid:0#body"></xop:Include>
</pri:DocumentData>
Here's the DocumentData of hte bad SOAP request:
<ns1:DocumentData>...</ns1:DocumentData>
So maybe that's the issue? If so then it's not clear to me how to make PHP use xop:Include for the attachment.
The WSDL can be found at https://learn.microsoft.com/en-us/windows-hardware/drivers/print/ws-print-v1-1 (do Ctrl + F and find "Print Device Definition V1.0 for Web Services on Devices")
edit: I also tried converting the PDF to a PS as well but that didn't help. I thought that might make a difference because https://learn.microsoft.com/en-us/previous-versions/ff562064(v=vs.85) describes DocumentData as "Document PDL Data" and https://stackoverflow.com/a/39708917/569976 mentions PS and PCL as PDL's but not PDF.

Get external page content regardless of response type [duplicate]

This question already has an answer here:
Need response body of HTTP 500 with file_get_contents (PHP)
(1 answer)
Closed 8 years ago.
I'm working with an API that I recently noticed is failing in the code some of the time. I retrieve it via file_get_contents, and I'm getting the error "failed to open stream: HTTP request failed!"
I plugged the URL into the browser directly and I get back a response, so I was confused. I thought to check the headers, and I noticed its coming up 403, and I have to assume that's why its failing? When its not 403, it does work. The 403 only comes up when the API authentication fails, and I have code to check if the XML that comes back says its a failure.
So really the question is, how can I get back the code, regardless of if its a 403 or not. I was going to start using simplexml_load_file since I'm loading it into SimpleXML anyway, but if there is another method I can/should use, that advice would be great too.
EDIT: I've attempted a simple curl request, but unless I've done it wrong, its also failed:
$curlObject = curl_init('https://api.eveonline.com/account/Characters.xml.aspx?userID=8166034&characterID=91242713&apiKey=B174C8B7B4364048B8A44B8C494904059D50B942BB4748FD907FF1DBF3F18282');
curl_setopt($curlObject, CURLOPT_RETURNTRANSFER, 1);
$fileContents = curl_exec($curlObject);
curl_close($curlObject);
echo $fileContents;
I would wrap the handling as specified in the duplicate question and then throw a dedicated exception when you trigger that error-response:
$legacyKey = [
'userID' => '8166034',
'apiKey' => 'B174C8B7B4364048B8A44B8C494904059D50B942BB4748FD907FF1DBF3F18282',
];
$api = new EveApi($legacyKey);
$api->define('getAccountCharacters', 'account/Characters.xml.aspx', ['characterID']);
try {
$characters = $api->getAccountCharacters($characterID = '91242713');
} catch(Exception $exception) {
printf("Exception: %s; Code: %s; Message: %s\n", get_class($exception), $exception->getCode(), $exception->getMessage());
throw $exception;
}
In this example, the default handling from the EveApi would be to throw exceptions on such errors:
<?xml version="1.0" encoding="UTF-8"?>
<eveapi version="2">
<currentTime>2013-11-02 13:06:53</currentTime>
<error code="203">Authentication failure.</error>
<cachedUntil>2013-11-03 13:06:53</cachedUntil>
</eveapi>
Can be turned into an EveApiError then as this output shows:
Exception: EveApiError; Code: 203; Message: Authentication failure.
Fatal error: Uncaught exception 'EveApiError' with message
'Authentication failure.' in ...
That would not only wrap the error handling but also the API access allowing you to inject your own API for testing purposes.
Additionally you can wrap the different but common return types.

How to read .Net web service in PHP?

I have successfully read WSDL form SoapClient. I tried following to pass value to web method and read results:
$client = new SoapClient("restaurant.asmx?wsdl");
$param = array('search_keywords'=>$search_text);
$result = $client->__soapCall('getRestaurantsASP',$param);
print_r($result);
I got this error:
Fatal error: Uncaught SoapFault exception: [soap:Server]
System.Web.Services.Protocols.SoapException: Server was unable to process request. --->
System.Data.SqlClient.SqlException: Invalid object name 'basic_info_table'. at
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean
breakConnection) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException
exception, Boolean breakConnection) at
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() at
System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler,
SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject
stateObj) at System.Data.SqlClient.SqlDataReader.ConsumeMetaData() at
System.Data.SqlClient.SqlDataReader.get_MetaData() at
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior
runBehavior, String resetOptionsString) at
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior,
RunBehavior runBehavior in E:\webareas\gs937\aspservice.php on line 73
How can I send parameters to web method and retrieve values?
As suggested by DaveRandom, problem seems to be in service itself rather problem is in SQL query used for service.
Try using SoapUI (you can download it from http://sourceforge.net/projects/soapui/files/) and execute the service method from there.
SoapUI is a neutral client to test the webservices.
Hope it will help.
I had to add:
<webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
<add name="HttpSoap"/>
</protocols>
</webServices>
in Web.config file to get things working.

twitter api returning xml on one server, empty string on another

I have a php Twitter app which lets you mark tweets as favorite.
I'm doing something like this:
$fav = $twitter->createFavorite("xml", $get_id);//handles api call (using curl)
$fav_result = new SimpleXMLElement($fav);
On my localhost and on one online server all goes well: the tweet is marked as favorite, and the api call returns xml. On another online server, the tweet is also marked as favorite, but php gives an error: Fatal error: Uncaught exception 'Exception' with message 'String could not be parsed as XML'
On the second server, I seem to get an empty string as return value. When I look at the http status codes, when all is well I get a 200, but when things go wrong I get a status code of 0.
When I check the curl_error it says "Failed to open/read local data from file/application"
I think it has to do something with my server configuration. Does anyone have an idea what might be causing this?
I found the solution here: http://www.milk-hub.net/blog/2008/08/26/curl_error_26
Since no separate postvars are sent, you have to explicitly set the to an empty string:
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, '');

PHP fatal error: Uncaught exception 'Exception' with message

I have a PHP script that connects to an api and posts information to their systems, but when its trying to connect it throws a fatal error:
Fatal error: Uncaught exception 'Exception' with message 'Problem with
'http://apitestserver.co.uk:9000/Service.svc/Items' in
/var/www/html/e/connect_test.php:17 Stack trace: #0
/var/www/html/e/connect_test.php(39):
do_http_request('http://apitest....', 'hello') #1 {main} thrown in
/var/www/html/e/connect_test.php on line 17
If I send it to a PHP script which just grabs the IP then it works, but if I send it to the API it doesn't. My PHP script creates XML and then forwards to the server. I was getting errors so I just created the following smaller script purely to test the connection:
function do_http_request($url, $data, $method = 'POST',
$optional_headers = 'Content-Type: application/atom+xml') {
$params = array(
'http' => array(
'method' => $method,
'content' => $data
)
);
if ($optional_headers !== null) {
$params['http']['header'] = $optional_headers;
}
$ctx = stream_context_create($params);
$fp = fopen($url, 'rb', false, $ctx);
if (!$fp) {
throw new Exception("Problem with $url");
}
$response = #stream_get_contents($fp);
if ($response === false) {
throw new Exception("Problem reading data from $url");
}
$metaData = stream_get_meta_data($fp);
fclose($fp);
if(!preg_match('~^HTTP.*([0-9]{3})~',
$metaData['wrapper_data'][0], $matches)){
throw new Exception('MALFORED RESPONSE - COULD NOT UNDERSTAND HTTP CODE');
}
if (substr($matches[1], 0, 1) != '2') {
throw new Exception('SERVER REPORTED HTTP ERROR ' . $matches[1]);
}
return $response;
}
$data = 'hello';
$paul =
do_http_request('http://apitestserver.co.uk:9000/Service.svc/Items',$data);
echo $paul;
If I change the URL to a simple script on another one of our servers which just grabs the IP of the incoming connection and returns it:
$ip=$_SERVER['REMOTE_ADDR'];
echo 'IP equals = ' . $ip;
Then it works fine with no errors.
Update -
with errors on it throws the following warning, probably because the script is not sending the correct info to the API
Warning: fopen(http://apitestserver.co.uk:9000/Service.svc/Items)
[function.fopen]: failed to open stream: HTTP request failed! HTTP/1.1
500 Data at the root level is invalid. Line 1, position 1.
Also note that I can access the api server fine using fiddler to send manually created items across, its just when this script tries to connect and send data there is an issue. I wrote another quick script which connects and prints out the default response (an rss feed of submitted items)
When I run the 'main' connector script it throws the following two errors
Warning: fopen() [function.fopen]: php_network_getaddresses:
getaddrinfo failed: Name or service not known in
/var/www/html/e/sequence.php on line 65
Warning: fopen(http://apitestserver.co.uk:9000/Service.svc/Items)
[function.fopen]: failed to open stream: Operation now in progress
in /var/www/html/e/sequence.php on line 65
I would suggest using curl instead of fopen(). curl is both more flexible, and more secure. Many servers disable allow_url_fopen, curl also fails more gracefully when there are problems on the remote server.
I just tested the URL in my browser and got a connection error.
Maybe the problem is with their server (or you have the wrong URL)?
Edit:
Looks like ther server is throwing a 500 error - maybe because the data you're posting is invalid.
You could use a packet sniffer and check the exact data you're sending to the server (or use cURL as suggested by #acrosman)
apitestserver.co.uk doesn't respond to ping and the url is inaccessable. The API-server doesn't seem to be up.
or You can change the headers:
$optional_headers = 'Content-Type: application/json')
First error message suggests problems with apitestserver - it returns error code 500, which states for "Internal server error".
Second one informs that PHP can't resolve host name into IP address - I'd look into DNS configuration and/or hosts file.
Apparently 'fopen' function does not return proper stream. There can be many possibilities when that happens, but according to PHP manual, fopen function on fail should present E_WARNING message with proper commentary. It is possible that you have errors of that class silenced - call error_reporting(E_ALL) at the beginning of your script and look for some relevant error messages.

Categories