Tuesday, January 22, 2008

PHP Web Services with fopen ..

If you have done little bit of 'C' (at least up to the lesson 'File Handling'), you may have come up with the function 'fopen'.

In PHP you can use 'fopen' not only to open a file in your hard disk, but also to open resource over network, specially from the Internet. Simply you can emulate http, https or ftp client functionality with the fopen.

That is simply you may cheat your friends by writing a your own version of Google like this.

<h1>My Google</h1>

<?php
$fp = fopen("http://www.google.com", "r");

$google_html = fpassthru($fp);
echo $google_html;
?>


You may find out that fopen is just a http client (and load only what it asks to load), it doesn't load images, since they need some additional http request which is automatically done if you instead did this request from a browser.

I think it is clear what 'fopen' can do. Why not we use it to access 'REST' web services. Yea, it is possible. To access 'REST' web services you only need is a Http client and as I mentioned 'fopen' is a Http client.

Let me show you how to access some real web service with fopen. I take amazon web service for an example.


<?php

$query = "TEST";
$catagory = "Books";
/* Use your own amazon key,
You can get it from http://aws.amazon.com */

$amazon_key = "your_amazon_key";


$fp = fopen("http://webservices.amazon.com/onca/xml?".
"SubscriptionId={$amazon_key}&".
"Service=AWSECommerceService&".
"Operation=ItemSearch&".
"Keywords={$query}&".
"SearchIndex={$catagory}&", "r");


$res = fpassthru($fp);

// For now I m just echoing the output as it is
echo $res;

?>
... It is really simple.

Is that only what fopen can do?. Hm! do you believe that we can do simple 'SOAP' webservices with fopen?. If you have seen lot of 'SOAP' messages, that will not be a problem to write a simple SOAP request with 'fopen'.

That is you can have a good control of your HTTP Request associating a stream context with 'fopen'. A simple SOAP request may only need few http headers and request XML wrapped with 'soap' headers as 'POST' data.
you can create a simple stream context with php standard function 'stream_context_create'.

Here is how you may use the 'fopen' with stream_context_create to do a POST http request.


<?php

$data = "Here is my POST data";

$opts = array(
'http'=>array(

'method'=>"POST",
'header'=>"User-Agent: My Own Http Client\r\n".
"Content-length: " . strlen($data)."\r\n",
'content' => $data

)
);

$context = stream_context_create($opts);

$fp = fopen($url, 'r', false, $context);


/* you got the pointer to $fp, use any function like fgets, freed to read the buffer */
?>

So if i use 'fopen' to do a SOAP request to call the same amazon web service, it will be like this..

<?php

$query = "TEST";
$catagory = "Books";
/* Use your own amazon key,
You can get it from http://aws.amazon.com */

$amazon_key = "your_amazon_key";


$soap_msg = <<<XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<ItemSearch xmlns="http://webservices.amazon.com/AWSECommerceService/2007-10-29">

<SubscriptionId>${amazon_key}</SubscriptionId>
<Request>
<Keywords>{$query}</Keywords>

<SearchIndex>${catagory}</SearchIndex>
</Request>
</ItemSearch>
</soapenv:Body></soapenv:Envelope>

XML;

$opts = array(
'http'=>array(
'method'=>"POST",
'header'=>"User-Agent: fopen soap engine\r\n".
"Content-Type: text/xml;charset=UTF-8\r\n".
"SOAPAction: \"http://soap.amazon.com\"\r\n".
"Content-length: " . strlen($soap_msg)."\r\n",
'content' => $soap_msg

)
);

$context = stream_context_create($opts);

$fp = fopen("http://soap.amazon.com:80/onca/soap?Service=AWSECommerceService", 'r', false, $context);

$result = fpassthru($fp);

echo $resutl;

fclose($fp);


?>

1 comment:

Jason W. Thompson said...

Nice article. The POST example was most helpful. Thanks!