I use external libraries to communicate with external systems. Communication is via Soap.
I provide the library with a set of data in a simple way. She checks the data, sends the request, and receives the reply. Converts the response to its object and returns.
How can I access the SoapClient object without making changes to the external library?
For this object, I need the original data. Request, response, headers.
Is it possible to do?
EDIT:
A simple example of using one of the many external libraries:
class fedex {
public function trackShipment($number)
{
$trackRequest = new TrackServiceTrackRequest();
$trackRequest->WebAuthenticationDetail->UserCredential->Key = $this->getAccessNumber();
$trackRequest->WebAuthenticationDetail->UserCredential->Password = $this->getAccountPassword();
$trackRequest->ClientDetail->AccountNumber = $this->getAccountNumber();
$trackRequest->ClientDetail->MeterNumber = $this->getMeterNumber();
$trackRequest->SelectionDetails[0]->PackageIdentifier->Value = $number;
$request = new TrackServiceRequest();
return $request->getTrackReply($trackRequest);
}
}
$fedex = new fedex();
$result = $fedex->trackShipment('123456789');
How to get original xml with request and header that was sent by library without modifying it?
The TrackServiceRequest() object does not access the SoapClient() object.
Related
I'm using Goutte to make a webscraper.
For development, I've saved a .html document I'd like to traverse (so i'm not constantly making requests to the website). Here's what I have so far:
use Goutte\Client;
$client = new Client();
$html=file_get_contents('test.html');
$crawler = $client->request(null,null,[],[],[],$html);
Which based of what I know should call request in Symfony\Component\BrowserKit, and pass in the raw body data. Here's the error message I'm getting:
PHP Fatal error: Uncaught exception 'GuzzleHttp\Exception\ConnectException' with message 'cURL error 7: Failed to connect to localhost port 80: Connection refused (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)' in C:\Users\Ally\Sites\scrape\vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.
If I were to just use DomCrawler, it's non-trivial to create a crawler using a string. (see: http://symfony.com/doc/current/components/dom_crawler.html). I'm just unsure about how to do the equivalent with Goutte.
Thanks in advance.
Tools you decided to use make real http connections and are not suitable for what you want to do. At least out of the box.
Option 1: Implement your own BrowserKit Client
All goutte does is it extends BrowserKit's Client. It implements http requests with Guzzle.
All you need to do to implement your own client, is to extend the Symfony\Component\BrowserKit\Client and provide the doRequest() method:
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Request;
use Symfony\Component\BrowserKit\Response;
class FilesystemClient extends Client
{
/**
* #param object $request An origin request instance
*
* #return object An origin response instance
*/
protected function doRequest($request)
{
$file = $this->getFilePath($request->getUri());
if (!file_exists($file)) {
return new Response('Page not found', 404, []);
}
$content = file_get_contents($file);
return new Response($content, 200, []);
}
private function getFilePath($uri)
{
// convert an uri to a file path to your saved response
// could be something like this:
return preg_replace('#[^a-zA-Z_\-\.]#', '_', $uri).'.html';
}
}
$client = new FilesystemClient();
$client->request('GET', '/test');
Client's request() needs to accept real URIs, therefore you need to implement your own logic to convert it to a filesystem location.
Have a look at Goutte's Client for insipration.
Option 2: Implement a custom Guzzle handler
Since Goutte uses Guzzle, you could provide your own Guzzle handler that would load responses from files, instead of making real http requests. Have a look at the handlers and middleware doc.
If you're just after caching responses so you make less http requests, Guzzle provides support for this already.
Option 3: Use DomCrawler directly
new Crawler(file_get_contents('test.html'))
The only drawback is you'll loose some of convenience methods of the BrowserKit client, like click() or selectLink().
I need to query a WCF service in PHP, so that it can return an XML object back to me.
Previously I was able to do this using the http request and post method
$url = 'http://localhost:49000/';
//create the httprequest object
$httpRequest_OBJ = new httpRequest($url, HTTP_METH_POST, $options);
Using Soap. I can make a connection doing this:
// Create a new soap client based on the service's metadata (WSDL)
$client = new SoapClient("http://localhost:8731/FileUploadService?wsdl");
But how can I pass the XML object into the soap client and return a XML object.
If you really want to send a string containing the XML, you could use
$client->YourSoapMethodCall( new SoapVar($xmlString, XSD_ANYXML) ).
But it would be more convenient to feed parameters with an array or objects (which I use).
cf. http://andrecatita.com/code-snippets/php-soap-repeated-element-name/
I am using SoapClient to send some data from a PHP site to a .Net WCF service.
This is my (shortened for clarity) code:
$wsdl = '/var/www/libraries/MyWsdl.xml';
$myClient = new SoapClient($wsdl);
and later, the actual call:
try {
$res = $myClient->Foo($someParameter);
}
catch(SoapFault $e){
//...
}
catch(Exception $e){
//...
}
This works great when everything is online, and the error handling works if the destination server is down on the time Foo is called.
Problem is that the SoapClient constructor fails, if the destination server is down, even though i've provided it with a static XML file with the WSDL (in oppose to a URL like "http://www.destination.com/MyService?wsdl").
I believe this is happening because the WSDL contains a reference to another WSDL:
<wsdl:import namespace="http://MyCompany.Services" location="http://www.destination.com/MyService?wsdl=wsdl0"/>
This other WSDL contains the definitions of the call parameters.
So, how can I "Inline" the second "sub-WSDL" inside the original one?
Will this allow me to create a SoapClient without initiating a connection to the destination server?
This is my service definition:
[ServiceContract(Namespace = "http://MyCompany.Services")]
public interface IMyService
{
[OperationContract]
[XmlSerializerFormat(Style = OperationFormatStyle.Rpc, Use = OperationFormatUse.Literal)]
string Foo(string myParameter);
}
You can use the single WSDL-file extension from here: http://wcfextras.codeplex.com/
Note that when using .net4.5 there should be no need for it, as the default metadata endpoint now also generates single WSDL-files in addition to the linked versions.
To do that simply add "?singleWSDL” to the URI (source: http://msdn.microsoft.com/en-us/library/dd456789(v=vs.110).aspx)
I received a manual to internal SOAP interface of my partner. It says:
MyPARTNER web services are provided in the form of a SOAP interface. The service is available in this URL: https://justsomeurl.com:435/soap
then some bla bla about authorization etc. and then a part about Accessible Methods:
pull()
The PULL method is used for pulling data from the database. The method
receives a unique data based parameter under an internal name
requestXML. This parameter contains data in a structured XML format.
String pull(String requestXML)
The XML contains data required to make the request, and the response
data is sent back.
then some other methods, error codes, it's not important here...
The problem is that I'm totally unexperienced in SOAP so I don't know how to use this interface via PHP. I've tried to find some examples, tutorials and I am now little bit more informed about SOAP and its functionality but still haven't found any advice about how to use interface like this...
thanx for any help
Php comes with PHP SOAP libraries, that usually are included and enabled after a common php installation.
Yuo are asked to biuld the client part of the webservice pattern. Your partner should provide you the .wsdl of the web service. The wsdl describes the avialble method, the parameters they need and what they return.
Tipically parameters and return values are array structures
This could be a skeleton for your code:
//build a client for the service
$client = new SoapClient("partner.wsdl");
//$client is now a sort of object where you can call functions
//prepare the xml parameter
$requestXML = array("parameter" => "<xml>Hello</xml>");
//call the pull function this is like
$result = $client->__soapCall("pull", $requestXML );
//print the value returned by the web service
print_r($result);
Here follows a non-wsdl example
First the location paramater is the address the SOAP request will be sent to.
The uri parameter is the target namespace of the SOAP service. This is related to xml namespaces.
A sample code for you could be:
//for URI specification you should watch your partners documentation. maybe also a fake uri (like mine) could work
//build a client for the service
$client = new SoapClient(null, array(
'location' =>
"https://justsomeurl.com:435/soap",
'uri' => "urn:WebServices",
'trace' => 1 ));
// Once built a non-wsdl web service works as a wsdl one
//$client is now a sort of object where you can call functions
//prepare the xml parameter
$requestXML = array("parameter" => "<xml>Hello</xml>");
//call the pull function this is like
$result = $client->__soapCall("pull", $requestXML );
//print the value returned by the web service
print_r($result);
Here a useful link: http://www.herongyang.com/PHP/SOAP-Use-SOAP-Extension-in-non-WSDL-Mode.html
I have developed an ASP.NET Web Service that performs queries to a database. Now I am developing a PHP Web site that consumes the Web Service for anything that requires access to the database. I have written the following function which creates a new SoapClient to consume the Web Service:
function get_soap_client()
{
if (!file_exists('wsdl_path.txt')
return NULL;
if (!$file = fopen('wsdl_path.txt', 'r'))
return NULL;
$path = fgets($file);
fclose($file);
return new SoapClient($path);
}
I have already tested this function as means to get a client to a stateless Web Service, and it does work. For example, this is my Web site's login function (whose control flow is not affected by state):
function try_login($user, $pass)
{
$client = get_soap_client();
// ASP.NET Web Services encapsulate all inputs in a single object.
$param = new stdClass();
$param->user = $user;
$param->pass = $pass;
// Execute the WebMethod TryLogin and return its result.
// ASP.NET Web Services encapsulate all outputs in a single object.
return $client->TryLogin($param)->TryLoginResult;
}
Which in turn calls the following WebMethod:
[WebMethod(EnableSession = true)]
public bool TryLogin(string user, string pass)
{
SqlParameter[] pars = new SqlParameter[2];
pars[0] = new SqlParameter("#User", SqlDbType.VarChar, 20);
pars[0].Value = user;
pars[1] = new SqlParameter("#Pass", SqlDbType.VarChar, 20);
pars[1].Value = pass;
// The Stored Procedure returns a row if the user and password are OK.
// Otherwise, it returns an empty recordset.
DataTable dt = Utilities.RetrieveFromStoredProcedure('[dbo].[sp_TryLogin]', pars);
if (dt.Rows.Count == 0) // Wrong user and/or password
{
Context.Session.Abandon();
return false;
}
else
return true;
}
However, I don't know whether the Web Service's Context.Session data is preserved between consecutive requests made from SoapClient objects retrieved by get_soap_client(). So I have the following questions:
Is the Web Service's Context.Session data preserved between consecutive requests made from a SoapClient object retrieved by get_soap_client()?
Is the Web Service's Context.Session data preserved between consecutive requests made from different SoapClient objects retrieved on the fly as I need them?
If the answer to the previous question is "no", is there any way to serialize the SoapClient's session data into a PHP state variable?
Ah, you mean is it sending the SESSION ID. I imagine you'll need to call __setCookie manually to set a cookie with the SESSION ID to your web service.
http://php.net/manual/en/soapclient.setcookie.php