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.
I need to use SOAP to retrieve some data from a database. I'm not an experienced PHP programmer, that's why I need some help. The company which provides the webservice (WSDL) gave me login info and links to the svc and wsdl files. They also gave me an example in C# of how to connect:
var proxy = new ChannelFactory<ServiceReferenceWCF.IWebService2>("custom");
proxy.Credentials.UserName.UserName = login;
proxy.Credentials.UserName.Password = pass;
var result = proxy.CreateChannel();
var logged_in = result.loggedIn();
Here's my PHP code:
$wsdl_proto = 'https';
$wsdl_host = 'their_wsdl_host';
$wsdl_host_path = 'their_wsdl_path';
$namespace_proto = 'https';
$namespace_host = 'their_namespace_host';
$namespace_path = 'their_namespace_path';
$location = $namespace_proto.'://'.$namespace_host.$namespace_path;
$wsdl_url = $wsdl_proto.'://'.$wsdl_host.$wsdl_host_path;
$connection = new SoapClient($wsdl_url, array('location' => $location, 'soap_version' => SOAP_1_1, 'connection_timeout'=> 600,
'proxy_login' => "my_login", 'proxy_password' => "my_password"));
$functions = $connection->__getFunctions();
var_dump($functions);
$logged_in = $connection->loggedIn();
It hangs during the loggedIn() function call. This function is listed in the $functions variable, so it is valid. I tried some other functions provided by the service - the result is always the same: the script simply freezes. And by that I mean there is no response from the service and PHP waits for the loggedIn() function to finish. After it exceeds the timeout, I get an error: Error Fetching http headers in...
What am I doing wrong? How can I debug it?
UPDATE:
I tried every single thing you guys suggested. But I still didn't manage to solve the problem. I don't use a proxy. You can find the results below:
1. I installed the SoapUI. After configuring the request for the some_method function (creating a basic Auth with credentials) I received a response: An error occurred when verifying security for the message.
Ticking the Authenticate pre-emptively option didn't help. I searched for a solution to this error, but I didn't find anything.
2. I tried almost every imaginable combination of options for the SoapClient class. Here are some of them:
$connection = new SoapClient($wsdl_url, array(
'login' => "login",
'password' => "pass",
'trace' => 1,
));
The response headers are empty. The request headers:
REQUEST HEADERS:
POST /file.svc HTTP/1.1
Host: host
Connection: Keep-Alive
User-Agent: PHP-SOAP/5.6.16
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/file/some_method"
Content-Length: 221
Authorization: Basic HASH
REQUEST:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/"><SOAP-ENV:Body><ns1:some_method/></SOAP-ENV:Body></SOAP-ENV:Envelope>
Next combination:
$connection = new SoapClient($wsdl,array(
'login' => "login",
'password' => "pass",
'trace' => 1,
'connection_timeout' => 500000,
'cache_wsdl' => WSDL_CACHE_BOTH,
'keep_alive' => false,
));
The response headers are empty. The request headers are the same, as before.
3. Using this:
$connection->__setLocation('https://host.org/file.svc');
doesn't help. However when I set the location to the WSDL file instead of the SVC file, I get the following response:
HTTP/1.1 405 Method Not Allowed
Connection: Keep-Alive
Content-Length: 1293
Date: Wed, 23 Dec 2015 14:28:53 GMT
Content-Type: text/html
Server: Microsoft-IIS/7.5
Allow: GET, HEAD, OPTIONS, TRACE
X-Powered-By: ASP.NET
I'm sure that the WSDL service is not slow enough, to exceed the timeout (Ricardo Velhote suggested it).
4. I've got an XML configuration file provided with the C# example I mentioned earlier:
<client>
<endpoint address="https://host/file.svc" binding="customBinding" bindingConfiguration="custom" contract="ServiceReference1.file" name="custom" />
</client>
<bindings>
<customBinding>
<binding name="custom">
<security defaultAlgorithmSuite="Default" authenticationMode="UserNameOverTransport" requireDerivedKeys="true" includeTimestamp="true" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<localClientSettings detectReplays="false" />
<localServiceSettings detectReplays="false" />
</security>
<textMessageEncoding messageVersion="Soap11WSAddressing10" />
<httpsTransport maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" />
</binding>
</customBinding>
</bindings>
I tried to extend the SoapClient class as suggested here, but as you can guess it didn't work - the behaviour of the script is still the same.
According to your update and the XML configuration file provided with the example this Webservice appears to be using WS-Addressing so the regular SOAPClient will not work and requires it to be extended in order to support WS-Addressing.
This is the line that gives it away
<textMessageEncoding messageVersion="Soap11WSAddressing10" />
I have yet to use WS-Addressing but I was recently analysing an API for project we will be working on in the future that requires it.
Please take note of this project or this other project which may be useful (it's easy to search for more PHP WS-Addressing).
Again, I have only done research and do not have any hands-on experience to help you with actual code :)
[EDIT: Obsolete answer after the update]
First of all, you might be being mislead by the use of the variable proxy in the example code. They are probably referring to HTTP Basic Authentication and not a proxy.
Try replacing proxy_login and proxy_password with login and password.
However, having said that, if you are getting the WSDL it means that at least it's connecting and obtaining the information about the service (which is good).
In normal situations you do not need to specify location in SoapClient as it should be defined by the WSDL file. By setting the location parameter you are overriding what is set in the WSDL file and you may be pointing it to a location that does not exist.
Try ommiting the location and soap_version from the SoapClient constructor and let the library handle those parameter automatically:
$connection = new SoapClient($wsdl_url, array('connection_timeout'=> 600,
'proxy_login' => "my_login", 'proxy_password' => "my_password"));
On the other hand, perhaps you are dealing with an extremely slow Web Service. There are many parameters in PHP that may be affecting the time it takes to timeout and most likely they are well below your connection_timeout parameter:
default_socket_timeout
max_execution_time
You have missed proxy_host and proxy_port in the options... If you need proxy to work provide theese parameters:
....
$connection = new SoapClient($wsdl_url, array(
'location' => $location,
'soap_version' => SOAP_1_1,
'connection_timeout'=> 600,
'proxy_host' => '....', // Your proxy host
'proxy_port' => 8080, // Your proxy port
'proxy_login' => "my_login",
'proxy_password' => "my_password"
));
Your first action when coding in the language you don't really know should be using manuals and examples.
Here is a link to PHP Manual on SoapClient - http://php.net/manual/en/soapclient.soapclient.php
For debugging SoapClient you can pass "trace" argument. Quote from the manual: Setting the boolean trace option enables use of the methods SoapClient->__getLastRequest, SoapClient->__getLastRequestHeaders, SoapClient->__getLastResponse and SoapClient->__getLastResponseHeaders.
$client = new SoapClient("some.wsdl", array('trace' => true));
So, in your case if you want to see what is going wrong do this:
$client = SoapClient($wsdl_url, array('trace' => 1));
$result = $client->SomeFunction();
echo "REQUEST HEADERS:\n" . $client->__getLastRequestHeaders() . "\n";
echo "REQUEST:\n" . $client->__getLastRequest() . "\n";
echo "Response headers:\n" . $client->__getLastResponseHeaders() . "\n";
echo "Response:\n" . $client->__getLastResponse() . "\n";
Also, as was noted in another answer - you are setting proxy_login and proxy_password parameters in the request, which should only be used if you are using proxy server to connect to that WSDL service.
I am using soap call request to below URL using PHP SoapClient.
https://stagingxml.tamarindtours.in/Version1.0/BaseDetails.svc?wsdl
I have used follwing code.
$HeaderSecurity = array("UsernameToken"=>array("Username"=>"xxx",
"Password"=>"xxx",
)
);
$client = new SoapClient('https://stagingxml.tamarindtours.in/Version1.0/BaseDetails.svc?wsdl',array('trace' => 1));
$header[] = new SoapHeader("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","Security",$HeaderSecurity);
$client->__setSoapHeaders($header);
//$client->__setLocation("https://YourTargetLocation/"); if you have wsdl file you don't need to use this line
$REsponse = $client->GetCountries();
I am getting following error.
Fatal error: Uncaught SoapFault exception: [a:InvalidSecurity] An
error occurred when verifying security for the message. in
/opt/lampp/htdocs/wssoap.php:148 Stack trace: #0
/opt/lampp/htdocs/wssoap.php(148): SoapClient->__call('GetCountries',
Array) #1 /opt/lampp/htdocs/wssoap.php(148):
SoapClient->GetCountries() #2 {main} thrown in
/opt/lampp/htdocs/wssoap.php on line 148
Can you please help me out? Thanks.
Server may have an invalid SSL certificate.
If this error is not important for you, try to ignore SSL certificate check as explained here : https://stackoverflow.com/a/8447706/911718 (see comments too about allow_self_signed option)
Edit : Same error as you & error solved at https://stackoverflow.com/a/16794759/911718
How to set a REST API error handler, when API used as a module.
I'm getting an invalid 404 found exception in HTML response rather than a json/xml response.
this is the sample api URL with an invalid entry point
http://localhost.backend.com/api/v1/invalidentrypoint
here api is in a module and v1 in nested with api module.
the reponse is
Not Found (#404)
Unable to resolve the request "api/v1/invalidentrypoint".
The above error occurred while the Web server was processing your request.
Please contact us if you think this is a server error. Thank you.
I'm expecting a response like
**HTTP/1.1 404 Not Found
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8
{
"type": "yii\web\NotFoundHttpException",
"name": "Not Found Exception",
"message": "The requested resource was not found.",
"code": 0,
"status": 404
}**
please help.
Have you tried setting the response format to json?
just add to the config:
'response' => [
'format' => \yii\web\Response::FORMAT_JSON
]
here's some info from the yii documentation:
https://github.com/yiisoft/yii2/blob/master/docs/guide/rest-error-handling.md
Edit: using the yii define from ethan's comment
the define is "json" but it's a good pratice to use the defined const from Yii
I add the following to the constructor of my API Controller(s):
public function __construct(string $id, Module $module, array $config = [])
{
parent::__construct($id, $module, $config);
\Yii::$app->response->format = Response::FORMAT_JSON;
}
This allows me to specify JSON error responses for individual controllers.
I'm need a little help about WS SOAP Client in PHP.
I have a WS SOAP, restrict to my IP, but I don know almost anything about SOAP, I've already use SOAP with rails a long time ago.
If I access the SOAP server from my browser using this: http://thedomain.com/wssitedsv/site.asmx/RetornaGanhadores
The server return me the correct XML.
If I access the SOAP server from my browser using this:
http://thedomain.com/wssitedsv/site.asmx?wsdl
The server return a xml with configuration of the SOAP
In the PHP I'm doing it:
$url = "http://thedomain.com/wssitedsv/site.asmx?wsdl";
$client = new SoapClient($url);
$return = $client->RetornaGanhadores(NULL);
echo $return;
And I'm getting this error:
PHP Fatal error: Uncaught SoapFault exception: [HTTP] Could not connect to host in /Users/sidnei/Sites/suasorte/scripts/get_data.php:15
\\nStack trace:
\\n#0 [internal function]: SoapClient->__doRequest('<?xml version="...', 'http://192.168....', 'https://www.tte...', 1, 0)
\\n#1 /Users/sidnei/Sites/suasorte/scripts/get_data.php(15): SoapClient->__call('RetornaGanhador...', Array)
\\n#2 /Users/sidnei/Sites/suasorte/scripts/get_data.php(15): SoapClient->RetornaGanhadores(NULL)
\\n#3 /Users/sidnei/Sites/suasorte/index.php(2): include('/Users/sidnei/S...')
\\n#4 {main}
\\n thrown in /Users/sidnei/Sites/suasorte/scripts/get_data.php on line 15
I can get all methods from Server using this:
$url = "http://thedomain.com/wssitedsv/site.asmx?wsdl";
$client = new SoapClient($url);
$return = $client->__getFunctions();
print_t $return;
What I am doing wrong to use this SOAP server?
How use a SOAP Server in PHP?
I appreciate any help.
Thanks