California Ajax Solutions Team

www.CalAST.com

In this article, we will explain an Ajax-like technique (it isn't really Ajax) that can be used to solve the problem of accessing server-side code running on another computer that's neither the client machine nor the web server. Of course, it will make more sense if you understand why you would want to do such a thing in the first place, so we will start there.

As you should know by now, the web is a client-server system. The browser runs on the client machine, and processes web pages delivered to it by a web server. Code to support a web application can run on either the client machine or the server machine, and often runs on both. But for security reasons, there are many restrictions that apply to client-side code (generally JavaScript). One of the obvious ones if you have written much JavaScript is that it has no file input or output capability. That's for good reason. You could load a web page that would have its embedded code start reading files on your hard drive, or (worse) start writing files to your drive. So just leaving such a possibility out of the run-time environment for the JavaScript language solves that problem.

Another security restriction (and a good one) is the "same source" policy. That is, if you load a web page with embedded JavaScript and it tries to start issuing Ajax requests to a different server from the one that delivered the web page, the browser should simply refuse to do so. You might get an error message, or you might just never get a callback - since the request was never issued in the first place. Again, if you think about this, it's a pretty good idea from a security viewpoint. Malicious JavaScript code could use server-side code on the third machine to wreak havoc on your system. Of course, malicious code could cause plenty of damage running off the same server, if it really wanted to. But modern security software will generally warn you about going to malicious sites. It would be much more difficult to catch it at the XmlHttpRequest level (see the Ajax Overview).

But there are times when you really need some functionality that is not available on your web server but might be available somewhere else under your control. Here's an example. Suppose you have a small business and don't have the resources to develop your own ecommerce solution. So you pick one of the ecommerce web sites to let your customers know about your products. Since server-side code is even more potentially dangerous than client-side code, most of these sites will only let you run their code - not yours. Again, this is a pretty sensible decision, since they don't want poorly written code to bring down someone else's on-line store by causing problems on a shared host.

But suppose your store has special needs that can't be met by the ecommerce software? Here's an example we ran into recently. Most ecommerce sites will provide inventory tracking. But if your inventory level drops to zero, then customers are blocked from placing an order. That might not be what you want, because you might be able to special order the item and you do want the customer to order it. So, you can turn off inventory tracking, but then there's no simple way to show if the item is in stock or not. The real solution is to have some server-side code that can show you whether the item is in stock or not, even if inventory tracking is off, to allow special orders. There's kind of a "you can't get there from here" flavor to this argument, but it happens in the real world.

The problem could be easily solved if you could write a small program that ran on a different server and looked things up in your database, not the one on the ecommerce site. But most of these sites won't let you put such code on their machines to protect their system integrity. If you have another site that does have this information, you could send it a query and display the results, right? Well, no. You could do this with server-side code, but you can't have that. And you can't do it with a client-side Ajax request because it violates the same source rule. So, are we out of luck?

No, we are not. And the reason is that there is a technique that does allow you to send a query to another system but not using Ajax. We will show you how to do this with the very popular jQuery library, which has built-in support for it.

JSON is an acronym for JavaScript Object Notation. It looks very much like JavaScript inline data, and serves a similar function to XML in the Ajax world, except it's easier to use from JavaScript, and it's lighter weight since it does not carry all the overhead of an XML document. JSONP is an extension of JSON that returns a result as a function call with an argument that is a JSON object. Of course, the callback function is in JavaScript, so it knows what to do with that argument. This all sounds relatively strange, but an example will set things to rights.

So, suppose you have a small controller program (in the Model-View-Controller sense) that looks up a part number and returns the stock on hand for that part. In JSON, this result would look like:

{ "stock": 1 }

which says it is an object (the curly braces) containing one property called "stock" whose value is 1. It can be arbitrarily complex, but in this case we don't need anything more. In JSONP, what you want the controller to return is a function call with this object as its argument:

json1234({ "stock": 1 });

So, what is this "json1234" name? It's just an example to indicate that it will be some synthetic name that you emit. Where does it come from? In jQuery, it will be passed to the controller program as an argument, and you just send it back. Now let's look at the controller itself, here in PHP. We will skip the actual lookup, since it will be very system-dependent. It could come from a file, or a database, or some other source.

<?php
/**
* Controller to do a file lookup of a part number for a stock check

* Arguments:
*   callback: the name of the callback function to emit
*   pn: part number to look up
* Returns:
* -1 if file can't be opened
* -2 if no part number provided
* stock on hand (0 if unknown part)
*/

echo $_GET['callback']."(";
if (empty($_REQUEST['pn'])) {
  echo '{ "stock": -2 });';
  return;
}
$partnumber = $_REQUEST['pn'];

$stock = "0";
/* Look up the stock level for $partnumber somehow and assign it to the variable $stock */
echo '{ "stock": '.$stock.' });';
?>

There's not much to it, since we skipped the hard part of determining the answer. We just want to show the code needed to provide the output in some meaningful (and proper) form.

The above code goes on the "auxiliary" server - the one that's not your ecommerce site. So, what does go on the ecommerce site? Basically, we need some fairly simple JavaScript that will take the part number, do the lookup, and use the callback function to modify a region of your web page. Where the part number comes from can vary greatly, but we will make the assumption that you know what part number is "in play" at any given time and where you want to look it up. So we need a function to do the lookup, and a place to put the answer, and that's about all.

What you do need to understand thoroughly is that the callback is somewhat ephemeral. Since it exists only for a very brief time, it needs to store the answer immediately where the user can see it. Let's assume that the "other" domain (the one that knows the answer) is just called myOtherDomain.com and that it has a subdirectory for Controllers with the above code as getStock.php in it.

function InventoryStockMsg(sku) {
  var url = "http://myOtherDomain.com/Controllers/getStock.php";

  $.ajaxSetup({cache:false});
  $.getJSON(url+"?callback=?&pn="+sku,
    function(data) {
      $(".VariationProductInventory").html(data.stock);
    }
  );
  return "Checking...";
}

We find it helps to turn caching off, so we do that first. We then issue the jQuery call getJSON, passing it the URL, appended with the string "callback=?", and the sku argument to the function as pn - that is, the part number to look up. The second argument to getJSON is the callback function, which will receive the emitted JSONP as its argument data. Note that it is anonymous, and will be assigned a made-up name by jQuery. Because jQuery checks to see if the request is to another domain, it will not issue an Ajax XHR - which would not work.

The InventoryStockMessage function returns a string, which can be written someplace if desired. The anonymous function writes the answer to DOM elements of class VariationProductInventory, so you must have one in your web page if you don't want the information to become lost. Of course, it does not do this until the callback happens. There may be a brief delay as messages are passed between the client machine and the other server.

This is admittedly an obscure-looking technique until you get used to it, but it does work. If you need help, please feel free to send us a message as noted on the contact page. We are happy to answer simple questions for free as time permits, or to provide consulting services for a fee.