PHP DevCenter

oreilly.comSafari Books Online.Conferences.

We've expanded our LAMP news coverage and improved our search! Search for all things LAMP across O'Reilly!

Search
Search Tips

advertisement

Print Subscribe to PHP Subscribe to Newsletters

PHP Web Services Without SOAP

by Adam Trachtenberg, coauthor of PHP Cookbook
10/30/2003

In an earlier article, I outlined the basics of Web services and how you can use PHP and SOAP to talk to Amazon.com. But SOAP isn't the only way a developer can query Amazon's database. The other method is known as REST, which stands for Representational State Transfer.

REST, unlike SOAP, doesn't require you to install a separate tool kit to send and receive data. Instead, the idea is that everything you need to use Web services is already available if you know where to look. HTTP lets you communicate your intentions through GET, POST, PUT, and DELETE requests. To access resources, you request URIs from Web servers. Further, what's wrong with the seemingly umpteen-gazillion already existing ways to process XML? Between SAX, DOM, XSLT, XSL-FO, XPath, XQuery, XPointer, and XWhatever, you should be able to harness at least one of them to turn XML into whatever form you desire.

Therefore, REST advocates claim, there's no need to layer the increasingly complicated SOAP specification on top of these fundamental tools. For more on REST, see the RESTwiki and Paul Prescod's pieces on XML.com.

There may be some community support for this philosophy. While SOAP gets all the press, there are signs REST is the Web service that people actually use. Since Amazon.com has both SOAP and REST APIs, they're a great way to measure usage trends. Sure enough, at OSCon, Jeff Barr, Amazon.com's Web Services Evangelist, revealed that Amazon handles more REST than SOAP requests. I forgot the exact percentage, but Tim O'Reilly blogged this number as 85%! The number I do remember from Jeff's talk, however, is 6, as in "querying Amazon using REST is 6 times faster than with SOAP".

In my previous article, I showed how to query Amazon using SOAP and then print HTML based on the data returned. In this article, I recreate the same results using REST instead of SOAP. This helps with a comparison between the two. If you haven't read the earlier article yet, now is a good time to skim it if you're unfamiliar with the basics of SOAP and the Amazon.Com Web services SOAP API.

The first task is finding the top selling O'Reilly books on Amazon.com. For that, you create an HTTP GET request to Amazon's Web Services URI. In REST, when a URI receives a GET request, it knows to process the request and return data to the client without altering the original information.

But before you can send the request, you need a way to let Amazon know what you're looking for. REST uses the query string to pass along the appropriate parameters, so you need to build it one argument at a time:

$base         = 'http://xml.amazon.com/onca/xml3';
$query_string = '';

$params = array( 'ManufacturerSearch' => "O'Reilly",
    'mode'  => 'books',
    'sort'  => '+salesrank',
    'page'  => 1,
    'type'  => 'lite',
    'f'     => 'xml',
    't'     => 'trachtenberg-20' ,
    'dev-t' => 'XXXXXXXXXXXXXX' ,
);

foreach ($params as $key => $value) { 
    $query_string .= "$key=" . urlencode($value) . "&";
}

$url = "$base?$query_string";

The $params array contains the details of the search: you want to find books published by O'Reilly with the results ordered by salesrank. These parameters are similar (differing in name) to the information provided to Amazon earlier for the SOAP request.

The only new item is f, for format. When you use SOAP, Amazon has to reply with a SOAP packet. When you use REST, Amazon is most likely going to reply with an XML document, but this is less a rule than a guideline. f is set to xml so that's what you get. Later we'll see how to instruct Amazon to reformat the data using XSLT by altering the value of f.

The foreach iterates through $params and constructs a properly formatted and encoded query string. Terms like O'Reilly with its apostrophe must be urlencoded into O%27Reilly or the request won't be valid.

Next you need to send the request and receive Amazon's reply. The file_get_contents() function is the easiest way to do this:

$xml = file_get_contents($url);

Unfortunately, file_get_contents() is only available on PHP 4.3.0 and above. Plus, fopen wrappers need to be enabled to let file_get_contents() access remote files. An alternative method is to use cURL:

$c   = curl_init($url);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$xml = curl_exec($c);
curl_close($c);

When CURLOPT_RETURNTRANSFER is set to 1, cURL stores the file as a variable instead of echoing it out.

The XML looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<ProductInfo 
  xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation=
    "http://xml.amazon.com/schemas3/dev-lite.xsd">

    <Request>
        <Args>
        omitted for clarity
        </Args>
    </Request>

   <TotalResults>828</TotalResults>
   <TotalPages>83</TotalPages>
   <Details url="http://www.amazon.com/...">
      <Asin>0596004508</Asin>
      <ProductName>Mac OS X: The Missing Manual...</ProductName>
      <Catalog>Book</Catalog>
      <Authors>
         <Author>David Pogue</Author>
      </Authors>
      <ReleaseDate>October, 2002</ReleaseDate>
      <Manufacturer>O'Reilly & Associates</Manufacturer>
      <ImageUrlSmall>http://images.amazon.com/...</ImageUrlSmall>
      <ImageUrlMedium>http://images.amazon.com/...</ImageUrlMedium>
      <ImageUrlLarge>http://images.amazon.com/...</ImageUrlLarge>
      <Availability>Usually ships within 24 hours</Availability>
      <ListPrice>$29.95</ListPrice>
      <OurPrice>$20.97</OurPrice>
      <UsedPrice>$14.98</UsedPrice>
    </Details>

    insert nine more books here

</ProductInfo>

In order to parse the XML, you need to know its data layout. At the top of the XML, there's a link to Amazon's lite schema. You can also eyeball this document to discover the book-related information is located inside of the <Details> elements below the top-level <ProductInfo> root element.

Now that you have the data stored in $xml, it's time to transform it into something useful. That's probably HTML, but it could be SQL for database storage or RSS for weblog readers. Since this article compares Amazon's SOAP and REST APIs, it's the same HTML from the SOAP piece.

You can use any of PHP's XML parsing utilities to accomplish this task, but I use XSLT here for two reasons. Why? First, Amazon offers XSLT support, so this guarantees everyone can use XSLT. (I'll show how to do this later.) Second, I feel SAX is a tad bulky just to turn XML into HTML. Besides, XSLT exists for exactly this reason; if you not going to use it here, you're never going to use it. (That said, I'm quite sure more than one person is strongly on the side of never using it.)

If you're not familiar with XSLT, Bob DuCharme has a introductory primer on XML.Com. Before getting into the nitty gritty of XSLT processing in PHP, here's the XSL to create the HTML:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html"/>

  <xsl:template match="/">
    <xsl:apply-templates select="ProductInfo/Details"/>
  </xsl:template>
  
  <xsl:template match="Details">
    <div style="clear:left; width: 300px; padding:5px; 
      margin:5px; background:#ddd;">
    <a href="{@url}"><image src="{ImageUrlSmall}" 
      alt="{ProductName}" align="left"/></a>
    <b><xsl:value-of select="ProductName"/></b><br/>
    <xsl:apply-templates select="Authors"/><br/>
    Amazon.com Price: $<xsl:value-of 
      select="substring(OurPrice, 2)"/><br/>
    </div>    
  </xsl:template>

  <xsl:template match="Authors">
    By 
    <xsl:for-each select="Author">
      <xsl:choose>
        <xsl:when test="not(position() = 1)">
          <xsl:text> and </xsl:text>
        </xsl:when>
      </xsl:choose>
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Without going into too much detail, this breaks down into a few pieces.

After the obligatory set of headers, you create a template that matches /, the root element. Within that template only ProductInfo and Details elements are handed off for processing. Everything else is ignored. This is analogous to the foreach loop on $hits->Details from last time.

The Details template does most of the reformatting. The HTML is embedded within the template. Variable values are pulled out to fill in the changing pieces of data. Things are a tad confusing because variables are accessed in three different ways, as {@url}, {ImageUrlSmall}, and <xsl:value-of select="ProductName">. In brief, the first grabs an attribute of the existing element. The second finds the value of a child of the current element. The last does the same thing, but it's used when you're not filling in a tag's entities.

Unfortunately, processing the authors is a bit more complex. You want to separate each author's name with and. However, since XSLT lacks PHP's join() function, you can't just do:

join(' and ', $hit->Authors)

Instead, you need to write your own version of join(). The Authors template iterates through each Author using a foreach loop. For every author but the first, it adds " and " and prints the author's name by selecting ".", the character data of the current element.

To make things easier for later, this XSLT is stored locally in a file named amazon.xsl and placed directly under the document root.

Now here's the code to use XSLT with PHP. This requires your copy of PHP to have XSLT support. If the XSLT extension isn't enabled, and you're unable to install it, just keep on reading, and you'll see how to solve this problem.

$xsl  = file_get_contents('amazon.xsl');
$xslt = xslt_create();

// map the strings to arguments
$args    = array('/_xml' => $xml, '/_xsl' => $xsl);
$results = xslt_process($xslt, 'arg:/_xml', 'arg:/_xsl', NULL, $args);

xslt_free($xslt);

Just as you loaded the XML file into $xml using file_get_contents(), you also store the XSLT file in $xsl. Then you instantiate an instance of the XSLT processor by calling xslt_create().

When you call xslt_process(), the first argument is the resource handle. The second through fourth arguments are the XML, XSLT, and output files, respectively. Passing in NULL as the output filename makes xslt_process() return the transformed document, where it's stored in $results. The final argument is the $args array. By default, xslt_process() loads documents from the file system; using $args instructs the processor to access data stored in the PHP variables $xml and $xsl instead.

Here are the results:

reformatted book data
Figure 1. Reformatted book data from the Amazon database

If your copy of PHP doesn't support XSLT, all is not lost. Amazon.com makes an XSLT service available, which you can use instead. It's easy to do.

First, place the stylesheet in a publicly accessible place on your Web server, such as http://www.example.com/amazon.xsl. Next, instead of assigning the f parameter in your REST request to xml, set it to the URL of your XSLT document. This causes Amazon to request the stylesheet, pass it to its XSLT processor, and return the transformed file to you instead of the XML.

$base         = 'http://xml.amazon.com/onca/xml3';
$query_string = '';

$params = array( 'ManufacturerSearch' => "O'Reilly",
    'mode' => 'books',
    'sort' => '+salesrank',
    'page' => 1,
    'type' => 'lite',
    'f'    => 'http://www.example.com/amazon.xsl',
    't'    => 'trachtenberg-20',
    'dev-t'=> 'XXXXXXXXXXXXXX',
); 

foreach ($params as $k => $v) { 
    $query_string .= "$k=" . urlencode($v) . "&";
}

$url = "$base?$query_string";

$results = file_get_contents($url);

Foisting your XSLT onto Amazon drastically simplifies your PHP. There's no need to manually invoke the XSLT program or even touch the XML. On the other hand, you're forced to use XSLT, which some might claim is a faustian bargain.

To make a more complex search, such as finding books published by O'Reilly on PHP, turn ManufacturerSearch into PowerSearch and update the search terms:

'PowerSearch' => "publisher:O'Reilly AND keywords:PHP"

This one line change filters our results down to four books:

A filtered search
Figure 2. A filtered search

The REST PowerSearch parameter accepts all the syntactical variations as its SOAP counterpart. That makes it just as powerful and easy for you to port your query logic from SOAP to REST and vice versa.

That's a quick tour of using Amazon.Com's REST Web services API. Unlike SOAP, an additional extension isn't necessary, nor is there all the associated overhead that comes from converting data structures from PHP to XML and back again. Instead, you have a leaner process that increases transparency and efficiency. However, that comes at the expense of requiring additional lines of code. Plus, you need to understand more about using HTTP and XML processing.

That can be a plus, not a minus. Once you have a good grasp of the basics, debugging REST is simple, since you can easily understand what's going on. In contrast, with SOAP, tracking down a bug can be a complicated mess, as you trace through SOAP packets and specifications.

Adam Trachtenberg is the manager of technical evangelism for eBay and is the author of two O'Reilly books, "Upgrading to PHP 5" and "PHP Cookbook." In February he will be speaking at Web Services Edge 2005 on "Developing E-Commerce Applications with Web Services" and at the O'Reilly booth at LinuxWorld on "Writing eBay Web Services Applications with PHP 5."

PHP Cookbook

Related Reading

PHP Cookbook
By David Sklar, Adam Trachtenberg


Return to the PHP DevCenter.


Comments on this article
Full Threads Oldest First

Showing messages 1 through 24 of 24.

  • Where to locate php fiel on web service
    2008-04-14 15:53:14  japuentem [View]

    i build a web service and i want to create a client to consuming the service, the client are created in php but i don't know where to locate the php file
  • Passing parameters in URL itself, is it safe?
    2007-01-29 23:18:38  Raja.p.Nagarajan [View]

    Dear sir!

    In REST style web services we are passing parameters to particular web service. I think this kind of passing doesn't have well security messure.

    Please Security issues in REST style web services. Since i dont know about that clearly.
    • Passing parameters in URL itself, is it safe?
      2007-01-30 01:40:03  Raja.p.Nagarajan [View]

      ok
  • How Unaware users know about the parameters of the particular web service?
    2007-01-29 23:11:31  Raja.p.Nagarajan [View]

    Dear Sir!

    Suppose one new user trying to access some web service in REST way. But he/she dont have clear idea about the parameters need to pass to that web service.

    I read one statement from one site.In that WSDL not important for REST based web services. So how can new user aware of parameters need to pass to a particular web service?
    • How Unaware users know about the parameters of the particular web service?
      2007-01-30 00:53:07  Raja.p.Nagarajan [View]

      hi
  • Source code
    2006-11-15 12:14:26  Loreen [View]

    Please, can you put a complete example of this?
    I mean, what code must be in wich file.

    Cause maybe I don't understand it all.
    Whatever, thanks and good work =)
  • error
    2006-07-23 10:25:52  digitalusmedia [View]

    i keep getting a permission error:

    [function.file-get-contents]: failed to open stream: Permission denied in...

    is there something i need to configure on my server to use this function?
  • Amazon Sales Rank
    2005-08-11 15:54:59  romej.com [View]

    track sales rank data using tips from this article at http://www.romej.com/rankforest
  • SOAP v. REST
    2005-03-03 08:17:55  jlines79@yahoo.com [View]

    This was a great article, I wanted to a make a comment about the fact that Amazon processes more REST requests than SOAP.

    In my own personal experience the AWS soap implementation is fairly unconventional. I tried getting it to work using both PEAR:SOAP and nuSoap. Neither one was able to properly consume the AWS SOAP. There are also documented problems using MS .Net with amazon soap. I don't think AWS is a very good example of a SOAP webservice.
    • SOAP v. REST
      2007-06-14 17:36:21  mindilator [View]

      I agree that AWS is not a usual SOAP implementation, but I thought it worth noting that I used PHP5's native SoapClient object to access AWS and I had zero problems consuming the service. The only thing I would consider awkward about it is their documentation. They don't make it very clear very early what types of parameters to pass to the functions, and if they're arrays, which elements.

      Yes, I realize there are a bajillion PHP 4+ sites out there that can't use that native function, but really now...you've had over 2 years to convert your site to PHP5. And you know you should. I sympathize with PHP4 guys, but only so much. We're almost at PHP6 now, for cryin' out loud. </rant>
      • SOAP v. REST
        2007-06-14 17:38:48  mindilator [View]

        *native object* sorry, not function
        • omg i'm dumb
          2007-06-14 17:42:41  mindilator [View]

          I should prolly check timestamps huh... my bad...
  • Connect to SOAP without SOAP
    2004-11-23 02:07:39  lemms [View]

    Amazon gives SOAP APIs, but assuming it does not have REST APIs, how do I connect to Amazon if REST is all I do? Does that mean I have to write out my own parser?

    I'm only familar with PHP and general XML. Not familiar with SOAP so I hope this don't sound silly!
  • saops vs PHP
    2004-10-14 14:59:01  bizopp [View]

    My webmaster is proficient with PHP, but I would like to know what are the main advantages to SOAP over PHP?
    david
  • Source Code
    2004-01-20 17:37:06  bvalk [View]

    I think REST seems great, and I'm trying to implement it. I've copied the code listed in the article and read up on the functions I needed more info on, but sadly, it doesn't want to work for me I get only a blank page, with just the html header tags in the source of my page. Is there anywhere available that can show me rest working? Particularly is the source code for the example in this article available anywhere? Is there any tutorial availble that shows how to set up a server.
    • Source Code
      2005-09-11 18:32:43  botheredbybees [View]

      try: echo $results; after the call to xslt_process
  • other values as params
    2003-11-05 03:44:37  anonymous2 [View]

    I was wondering where I could get more information on what values the $params->key would accept.

    Suppose I want to list all the top selling video games on amazon, how do I proceed?
    • Adam Trachtenberg photo other values as params
      2003-11-05 21:54:32  Adam Trachtenberg | O'Reilly Author [View]

      Check out Amazon's Web services home page at: http://www.amazon.com/webservices/ for the full scoop. I'd point you directly at the API Guide, but I can't find it linked to on their site. But, if you download their SDK kit, it's all there.

      In the meantime, however, try setting the "mode" parameter to "videogames" and see if that works for you.
  • Very interesting
    2003-11-05 03:42:00  spencerpieters [View]

    Hi,

    Great article, got great results in no time. Are there websites that describe how to create the scripts that run on the other side of the story, ie how do we write our own webservices in PHP for example ?
    • Very interesting
      2003-11-05 05:45:45  spencerpieters [View]

      Never mind, i figured it out. Just query your database or any other datasource, generate xml and spit it out. :-))

      Absolutely wonderful article !!
      • Adam Trachtenberg photo Very interesting
        2003-11-05 22:00:28  Adam Trachtenberg | O'Reilly Author [View]

        Yup! All you need to do is parse the input and print out some XML.

        The key is publishing an API that people can depend on. I know Amazon's gone through three iterations of theirs, but they've always associated a new version with a slightly changed URL. So people can tell them apart and update accordingly.
  • Intro to REST
    2003-11-01 04:34:44  peej [View]

    I wrote an introduction to REST a while ago that may interest people: http://www.peej.co.uk/rest/
  • Screen shaping
    2003-10-31 05:33:33  anonymous2 [View]

    If content is output with XHTML and makes wise use of CSS, by definition is makes it ideal for screen shaping.

    Whether it is ideal in terms of being a "coarse grained API" is another question (users don't like being flooded with information) - with a REST based API as you've described, there's alot more room to publish a fat API.

    That said the advantage of using XHTML, with data clearly defined with id/class attributes, is the provider only needs to build one interface.

    http://simon.incutio.com/archive/2003/10/21/xpathRocks
    • Adam Trachtenberg photo Screen shaping
      2003-10-31 08:15:23  Adam Trachtenberg | O'Reilly Author [View]

      I have a few thoughts:

      One: There's nothing wrong with using REST and XPath in unison. After you've queried the site with REST, you can make a DOM object, perform some XPath magic, and then then feeding the result set to an XSLT processor. I've recently become a big fan of XPath, as I've started to play with PHP 5's SimpleXML extension, which has integrated XPath query support.

      Two: That article implicitly implies that you have complete control over the input XHTML files. With a published REST interface, there's at least the hint of a promise of a fixed API. If you're screen scraping (regardless of the legalities involved), there's no social contract between you and the site to maintain a working relationship. (i.e. They can redesign their data model at any time and potentially break your scripts.) If a site publishes a REST interface, then you know it's unlikely to shift without warning.

      Three: For your own site, OTOH, you may want to make your REST interface a front-end for an XPath query of your XHTML documents, but that assumes all those documents actually exist as real files on the hard drive or are stored in a XML database. If you're Amazon, you probably don't have millions of individual HTML files; they're probably springing out of some SQL databases into a template, so I don't think that's really an option here.


Recommended for You

Tagged Articles

Post to del.icio.us

This article has been tagged:

php

Articles that share the tag php:

Understanding MVC in PHP (477 tags)

The PHP Scalability Myth (123 tags)

The Dynamic Duo of PEAR::DB and Smarty (53 tags)

PHP Form Handling (43 tags)

Very Dynamic Web Interfaces (39 tags)

View All

rest

Articles that share the tag rest:

How to Create a REST Protocol (349 tags)

The REST of the Web (135 tags)

Show Me the Code (133 tags)

Implementing REST Web Services: Best Practices and Guidelines (122 tags)

Putting REST on Rails (73 tags)

View All

webservices

Articles that share the tag webservices:

How to Create a REST Protocol (74 tags)

The REST of the Web (32 tags)

Implementing REST Web Services: Best Practices and Guidelines (31 tags)

Yahoo! Web Services (27 tags)

An Introduction to Service-Oriented Architecture from a Java Developer Perspective (27 tags)

View All

xml

Articles that share the tag xml:

Very Dynamic Web Interfaces (595 tags)

Introducing del.icio.us (181 tags)

How to Create a REST Protocol (161 tags)

Secure RSS Syndication (112 tags)

XML on the Web Has Failed (109 tags)

View All

web

Articles that share the tag web:

What Is Web 2.0 (2258 tags)

Rolling with Ruby on Rails (686 tags)

Very Dynamic Web Interfaces (362 tags)

Ajax on Rails (183 tags)

A Simpler Ajax Path (136 tags)

View All

Sponsored Resources

  • Inside Lightroom
Advertisement

Sponsored by:

Sign up today to receive special discounts,
product alerts, and news from O'Reilly.
Privacy Policy >
View Sample Newsletter >
  • Youtube
  • http://www.youtube.com/OreillyMedia
  • Twitter
  • Subscribe
  • View All RSS Feeds >
O'Reilly Media

800-889-8969 or 707-827-7019
Monday-Friday 7:30am-5pm PT
©2011, O'Reilly Media, Inc.
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.
  • About O'Reilly
  • Academic Solutions
  • Contacts
  • Customer Service
  • Careers
  • Press Room
  • Privacy Policy
  • Terms of Service
  • Writing for O'Reilly
  • Community
  • Authors
  • Forums
  • Membership
  • Newsletters
  • RSS Feeds
  • User Groups
  • More O'Reilly Sites
  • igniteshow.com
  • makerfaire.com
  • makezine.com
  • craftzine.com
  • labs.oreilly.com
  • Partner Sites
  • PayPal Developer Zone
  • O'Reilly Insights on Forbes.com