I used Zend Framework 1.11 to make a REST web service in PHP using the Zend_Rest_server class but I wasn't able to intercept and analyze the responses from Zend_Rest_server instances before these are sent to the clients.
To make the REST web service I use this snippet of code:
$server = new Zend_Rest_Server();
$server->setClass('Ws_dummy', 'dummy');
$server->handle();
Is there a method to log responses because I need to analyze them and I wasn't able to find a way to solve this need.
Thank you in advance for any help you can provide.
P.S. For example in SOAP web services I can do this:
$server->setReturnResponse(true);
$response = $server->handle();
or
$server->handle();
$response = $server->getLastResponse();
and analyze the responses
You can log Requests like this:
$writer = new Zend_Log_Writer_Stream('/path/to/logfile');
$logger = new Zend_Log($writer);
$logger->info( Zend_Debug::dump( $_REQUEST, 'Request-Dump', false );
You should do that before the Rest_Server handles the Request.
If you got further Questions - just ask :-)
Edit (added some useful information):
It may be helpful to understand that Zend_Debug::dump() method wraps the PHP function var_dump(). If the output stream is detected as a web presentation, the output of var_dump() is escaped using htmlspecialchars() and wrapped with (X)HTML pre-tags.
Edit #2:
You can return the Response of Zend_Rest_Server with:
$server->returnResponse(true);
before $server->handle().
Edit #3:
Be aware:
If I've read everything right you need to send the Headers by urself if you are returning the Response.
You can get/+set the Headers with:
$headers = $server->getHeaders();
foreach( $headers as $header ) header( $header );
Related
I'm trying to send a response to an API for Oauth. Sadly, the Symfony2 docs do a poor job of explaining all the different parts of $response->headers->set(...);.
Here's my response section that's inside of my OauthController:
$response = new Response();
$response->setStatusCode(200);
$response->headers->set('Location', 'url=' . $auth_url);
return $response->send();
The controller must have a return statement so, does my code look good or how can I replicate header('Location: ' . $auth_url); from normal php?
Thanks!
Since you want to do a redirect, then you can use RedirectResponse instead of regular Response:
return new RedirectResponse($auth_url);
While #TomaszMadeyski does a good job providing you with a much better alternative, I wanted to take a minute and explain why your code does not work (as it's just fine).
The problem is that a controller much return a response, but it must not send the respond. If you look at the front controller, you'll see that it takes care of sending the response:
$response = $kernel->handle($request);
$response->send();
The reason behind this is that Symfony allows you to edit the response between the controller and the send() (e.g. to add an awesome toolbar or configure the content type).
If you're doing a redirect, shouldn't your HTTP response code be one of the codes in the 300 range to indicate a redirect?
Also, you might want to checkout this Symfony Cookbook article on redirecting.
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.
I'm writing my own Response class in PHP (as an exercise) in order to simplify the setting of headers and output. Currently, I'm using header() to send out HTTP headers after the request has been built but I'm not sure how to send the body. Do you just use print and echo? Or is there some a formal method?
You can use The HttpFoundation Component
A Response object holds all the information that needs to be sent back to the client from a given request. The constructor takes up to three arguments: the response content, the status code, and an array of HTTP headers:
use Symfony\Component\HttpFoundation\Response;
$response = new Response(
'Content',
Response::HTTP_OK,
array('content-type' => 'text/html')
);
As far as I know echo is the way to go. However, it is a best practice to separate your logic and design. A good way to do this is by using two php files for 1 page (for example pagelogic.php and layout.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.
I'm creating a web service using PHP5's native SOAP Methods. Everything went fine until I tried to handle authentication using SOAP Headers.
I could easily find how to add the username/password to the SOAP headers, client-side:
$myclient = new SoapClient($wsdl, $options);
$login = new SOAPHeader($wsdl, 'email', 'mylogin');
$password = new SOAPHeader($wsdl, 'password', 'mypassword');
$headers = array($login, $password);
$myclient->__setSOAPHeaders($headers);
But I can't find anywhere the methods for collecting and processing these headers server-side. I'm guessing there has to be an easy way to define a method in my SoapServer that handles the headers...
With a modern PHP version it is NOT necessary to add anything to the WSDL as the headers are part of the SOAP Envelope specification.
The user contributed example cited by Paul Dixon does not work simply because the header is not UserToken as written in the comment, the header is Security, so that's is the name the class method should have. Then you get a nice stdClass object with a UserToken stdClass object property that has Username and Password as properties.
Example code (to be inserted in a PHP class that implements the SOAP service:
public function Security( $header ){
$this->Authenticated = true; // This should be the result of an authenticating method
$this->Username = $header->UsernameToken->Username;
$this->Password = $header->UsernameToken->Password;
}
Works like a charm for Username/Password based WSSE Soap Security
SoapClient uses the username and password to implement HTTP authentication. Basic and Digest authentication are support (see source)
For information on implementing HTTP authentication in PHP on the server side, see this manual page.
If you don't want to use HTTP authentication, see this user-contributed sample on the SoapServer manual page which shows how you could pass some credentials in a UsernameToken header.
You can try reading RAW POST data.
if ( $_SERVER['REQUEST_METHOD'] == 'POST' )
{
$xml = file_get_contents('php://input');
print( htmlspecialchars( $xml ) );
// XML processing
}
In $xml you will have the whole SOAP XML request.
SoapServer does not have methods for reading SOAP headers.
--
edit: contributed example from manual does not seem to work, header handling method never gets called
You have to use a current version of PHP. With PHP 5.2.4 I had the same problem, but with 5.2.17 or 5.3.8 the callback for SOAP header handling (described in the user-contributed samle on php.net) gets called and everything works pretty fine.