Posts Tagged ‘web app’

Unity

I did a little experiment with meshing XML + HTML + PHP.

First, a little background info. Most service-side web technologies (PHP, Ruby on Rails, etc.) were designed around the concept of applying server-side markup to HTML,

<title><?php echo $title;?></title>

… which is interpreted and processed when the page is pulled. There are various frameworks and templating systems to make this easier, cleaner, more structured, etc. but the concept is the same. AJAX comes into play here and there, but it’s seen mostly as a way to sprinkle bits of dynamic data across a page.

This model was fine a few years ago, but for modern web services and apps I think there needs to be a push away from this model, primarily for 2 reasons:

  • Large portions, if not most, of the content of many web apps is dynamic, AJAX-queried data.
  • Support for mobile and desktop platforms connecting to web services is becoming increasingly important; platforms/apps for which HTML/CSS (or at least HTML/CSS designed for a browser) may not serve to provide the best UI.

AJAX structured code fits the bill.

A 100% AJAX architecture elegantly separates application logic (output as XML) from presentation (output as HTML/CSS). Unfortunately, 100% AJAX is not that easy for a complex application. JavaScript interpretation can be slow, killing frontend performance, and backend performance can suffer from the repeated flood of asynchronous requests. In addition, the latency from a multitude of AJAX requests+responses can quickly become noticeable (especially with a burdened backend and during an initial page load). When such issues become apparent, the solution always seems to be to go back to the messy world of hacking server-side tags into HTML.

Unity is an attempt to maintain a 100% AJAX application framework, but alleviate the issues mentioned above for web apps. It’s very, very simple; just a bit of glue that takes the XML from one or more AJAX calls (on localhost; the application server itself), turns it into JSON, and embeds it within the <head> element of the HTML document being served. This should not be done for every call, but for AJAX calls where the data being presented is “mostly static” (e.g. username, messages, etc.). The data can then be accessed in the client-side JavaScript and used as necessary.

Looking at the typical three-tier architecture, Unity is a bit of glue that sits above the app logic (technically, it could be thought of as part of the app logic, but it’s separated here for illustrative purposes).

app stack with glue

However, since the glue makes 1+ calls to fetch the XML from the app logic, things look a bit more like this on the backend:

backend app stack, multiple, with glue

As I mentioned, this is all very simple stuff. Here’s the code that does the magic:

class Unity
{
protected $js = null;
protected $htmlFile = null;

function __construct($_htmlFile)
{
$this->js = array();
$this->js[] = "var Unity = {}";

$this->htmlFile = $_htmlFile;
}

public function PushXml($_xmlFile, $_namespace)
{
$xml = simplexml_load_file($_xmlFile);

// see http://www.php.net/manual/en/function.json-encode.php#97008 for why json_encode is done like this
$this->js[] = "Unity.{$_namespace} = " . json_encode(new SimpleXMLElement($xml->asXML(), LIBXML_NOCDATA));
}

public function PushVar($name, $var)
{
$snippet = "Unity.{$name} = {$var}";
$this->js[] = $snippet;
}

public function UnifyAndEcho()
{
$scriptBlock = implode(';', $this->js);

$dom = new DOMDocument();
$dom->loadHTMLFile($this->htmlFile);
$head = $dom->getElementsByTagName("head")->item(0);

$scriptElem = $dom->createElement('script', $scriptBlock);
$scriptElem->setAttribute("type", "text/javascript");

if($head->firstChild)
{
$head->insertBefore($scriptElem, $head->firstChild);
}
else
{
$head->appendChild($scriptElem);
}

echo $dom->saveHTML();
}
}

Note that you don’t have to parse the XML; json_encode() takes the SimpleXMLElement object and converts the entire tree to JSON. This is done in order to:

  • keep Unity (and the glue layer) as brain-dead simple as possible
  • avoid mucking around with application logic at this level (if the XML doesn’t fits well [e.g. too big, too much unnecessary data, etc.] it’s a problem at a lower level)

Now an example of how the Unity class would be utilized:

$uni = new Unity("test-page.html");
$uni->PushXml("http://localhost/test-xml.xml", "Account");
$uni->UnifyAndEcho();

Assume the XML output is:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<account_info>
<username>
pixel</username>
<stats
timespan="month">
<check_ins>
12432</check_ins>
<photos>
123</photos>
<followers>
32</followers>
</stats>
</account_info>
</root>

… in the client-side JavaScript code, we can access any of this data via Unity.<namespace>… The namespace was specified as “Account”, so the variables can be accessed as follows,

// username
Unity.Account.account_info.username;

// stats.check_ins
Unity.Account.account_info.stats.check_ins;

// ...

Sessions

A not-too-obvious challenge in doing something like this handling session data. As Unity is calling scripts from localhost (and not the client’s computer), a different session, one for localhost, is active. In addition, session data is locked, preventing two active scripts from accessing the same session data (which the xml generating script may very well need)

First, here’s how to get the session id:

session_start();
$sess_id = session_id();
session_write_close();

session_write_close() closes the session so that the subsequent script call will be able to access it. If necessary, session data can be started and access again after or in-between Unity::PushXml() calls; however, again, Unity is meant to be just a lightweight bit of glue, there shouldn’t really be a need to read or manipulate session data at this point in the code.

We can now pass the session id as a GET parameter:

$uni->PushXml($localbase . "controller/getlogin.php?sid={$sess_id}", "Account");

Now within the script being called, session_id() needs to be called with the passed session id, before session_start().

if(isset($_GET['sid']))
{
session_id(
$_GET['sid']);
}

session_start();

That’s it.

Finally it’s worth mentioning that none of this is bound to PHP nor XML. This could be done in any server-side language and the app logic could just as easily output JSON.

hotspotdot

hotspotdot is my entry into Microsoft’s My App is Better Challenge. In a nutshell, hotspotdot allows you to locate and tag “hot spots” that are important to you, allowing you to create a personal database of hot spots.

It’s a very simple app, utilizing PHP, SQL Server 2008, jQuery, jQuery UI, and the Google Maps API. I wrapped thing up in under 2 weeks, but in order to make the August 25th deadline there were a few features I didn’t get a chance to put in, such as preloaders, icons on the map, and searching by tag. I’ll probably devote some time to these in the coming weeks.

hotspotdot login

The goal of the contest was to create something showing off the power of SQL Server and Microsoft’s new PHP for SQL Server 2.0 drivers. I used the new PDO driver which was pretty sweet – very simple, elegant API. Two things in particular that impressed me were transactions (very nice for doing multiple inserts or deletions) and a consistent and well designed exception model (makes error handling much easier and especially powerful when combined with transactions as failed queries don’t effect the database [code jumps to exception handler before commit() is called], so no chance of junk being inserted). Error messages, in general, were also much more descriptive than those I’ve encountered with MySQL.

Finding a server proved difficult. I got a shared hosting solution, but the host was unable (though I suspect unwilling) to install the PHP for SQL drivers. So I ended up getting a virtual private server, but this only came with SQL Server Express and I used some features (see below) that prevented a migration. In order to avoid purchasing an SQL Server 2008 license (way out of my budget), my final solution was use the shared hosting server for the DB and the VPS for everything else. Hence the reason for the site being located at the my. subdomain, which maps to the IP of the VPS.

SQL Server 2008 is a fine system (despite some annoyances with the management studio)… though it’s really just a solid database system, which isn’t bad, but there’s nothing really impressive or creative about that. It’s not really leaps and bounds above a cheap solution like MySQL. The contest was about SQL Server, so I tried to do something that utilized a fairly unique aspect of the system: the geography data type. I wasn’t too impressed. It simply holds a (longitude, latitude) pair in a certain format, nothing more. The one big advantage of having a vector type like this would be doing comparisons based on distance but, as far as I could tell, this isn’t supported (my queries failed). Worse yet, in SQL Server Management Studio the display of the geography type is in hexadecimal, making things very cryptic… I couldn’t help but wonder why this is any better than using 2 columns and storing the longitude and latitude values independently. That said, the idea of richer/more-complex data types within a relational database is a pretty cool idea and it would interesting to see it taken further and beyond its current, primitive state.

hotspotdot map

hotspotdot map

Leave a comment if you find a bug or have any questions, comments, etc.