[Secure AJAX for PHP] SAJA

SAJA v2.3+ Documetation

This page should help you understand the basics of SAJA.

Including SAJA in your PHP Application

Include saja.php on any page which is to run saja, and instantiate the saja class. You can call it anything you want, but in this example we use "$saja" as the class variable.

include($_SERVER['DOCUMENT_ROOT'].'/saja/saja.php');
$saja = new saja;

Once the class is instantiated, you must specify the path to saja. (relative URL to the directory which contains the 4 files, with leading and trailing slash)

$saja->set_path('/saja/');

You can also set the path permanently in saja.php so you only have to set it up once.

Setting the saja path in saja.php

...
class saja
{
	var $saja_path = '/saja/';  //The relative path to saja, with leading and trailing slashes
...

Enabling Full UTF-8 Support

By default, SAJA will handle the extended ASCII character set with no problems, so you'll be covered for most european languages. However, if you need to venture outside of ASCII range to include the full UTF-8 character set, you'll need to let Saja know. I set it up this way because PHP cannot normally handle UTF-8 properly, so I wanted the developer to have to conciously make this choice.

Enabling Full UTF-8 Support

$saja->set_true_utf8(true);
Why can't PHP handle UTF-8? How do I get around it?

PHP assumes that each character takes up 1 byte. Characters beyond index 255 in the UTF-8 character set take 2 bytes per character. Hence, PHP interprets and manipulates them as if they were twice the length.

Example of PHP's Inability to handle UTF-8

echo substr(SOME_UTF8_CHARACTER, 0, 1);
//returns only the first byte of the UTF-8 character
//outputs a regular 1-byte ASCII character
The Solution

To combat this problem, you'll need to use a UTF-8-aware string manipulation library for PHP, such as PHP UTF-8. Now any time you want to manipulate a string that might contain UTF-8 characters, be sure to use these functions instead of the built-in PHP ones.

Securing Client information via HTTP data encryption

SAJA has the ability to encrypt any data sent from the client to the server. Normally, when a password is sent via a regular HTML form, the data is sent plain-text! HTTPS is the true solution to this problem, but SAJA provides a way to do this without needing an SSL certificate or a server that is set up to handle HTTPS. The level of security SAJA provides is comprable to WEP (used on many home networks). The only difference is that SAJA generates a new key with each page load, so it is theoretically very hard to bust.

Securing HTTP Data

$saja->secure_http(); //encrypts all data sent by SAJA

//Once in your PHP functions the data is automatically decrypted and available for use.

For large amounts of data, this will slow down the response time of SAJA as a whole, because it will have to wait for the client to encrypt the data before it is sent.

The Status Indicator

Saja allows you to notify the end user that there is a process going on in the background. The indicator will work even if there are multiple saja requests running at the same time. Once all requests are complete, the indicator will dissapear. This is very useful to implement so that users do not become confused after hitting a button that does not have any immediate visual indicators.

The indicator is implemeneted as follows:

echo $saja->saja_status([{CSS STYLE STRING}[, {Display Text}]]);

For example:

echo $saja->saja_status('background-color:red; position:absolute; top:0px; left:0px');

This function will output the status indicator HTML SPAN element wherever it is echoed. This method should only be called once, as it is referenced by saja using a predefined Element ID named "sajaStatus". You can also set up the style of your status indicator in CSS by using the ID selector: #sajaStatus.

Styling the status indicator in your CSS file:

#sajaStatus{
	background-color:red;
	position:absolute;
	top:0px;
	left:0px;
}

Calling PHP Functions Using SAJA

Now that you are ready to start calling server-side functions with SAJA, here is a little insight on how SAJA operates:

SAJA is a scripting language, designed specifically for AJAX applications running in a PHP/JavaScript-enabled environment. The most basic functionality is structured as follows:

MyPHPFunction(ARGS)

In this case, you would be calling the function named "MyPHPFunction" in your saja.functions.php file.

Function arguments (ARGS) work just like calling a javascript function, and can be numeric values 1,2,3... string values, 'a','b','cat'... , DOM Elements, JS objects, JS variables, JS arrrays, and JS functions. Anything you input here will be converted into a PHP variable to be used in your back end code. JavaScript Objects are currently translated up to one level deep.

Let's say you had a single input box: <input type=text id=inputText>, a div somewhere on the page: <div id=myDiv>Content of myDiv</div> a global javascript variable: var myId = 'ABC123', a string: 'My name', and a number: 12345. Now you want to pass the raw values of all these things into a PHP function on your local server. ARGS would appear as follows:

(inputText:value, myDiv:innerHTML, myId, 'ABC123', 12345)

so the entire request would look like this:

MyPHPFunction(inputText:value, myDiv:innerHTML, myId, 'ABC123', 12345)

Notice the ":" (colon) operator. This is a shortcut to document.getElementById('id'), and whatever comes after it is the expected property i.e. "myelement:value".

Managing Your Function Libraries

By default, Saja only cares about the user-defined functions file "saja.functions.php". However, as your application grows, you will want to separate your saja functions into different files and locations. You can do this by using Saja's built-in library management system.

Below is an example of what a second user-defined functions library might contain. The only requirements are that you create a class extension of saja and call it myFunctions. Any functions in it will be callable by saja.

Barebones process file contents

<?php class myFunctions extends saja {

function someFunction(){
	echo 'hello world!';	
}
	
?>

If you want to change the default GLOBAL process file to something other than saja.functions.php, set it here:

Setting the default GLOBAL process file in saja.php. If Saja recieves no other attempt to set a process file, it will use the one set here.

class saja {
	...
	var $saja_process_file = 'saja.functions.php';		//default process file to use
	...

In the example below, any calls to the newly created $saja object will user the default path set by set_process_file() instead of the global one. This is useful if you have a lot of saja calls on the same page that need to use a certain process file.

Setting the default Class-level process file.

$saja = new saja;

//a process file in the saja root directory
$saja->set_process_file('someOtherFile.php');

//a process file relative to the saja root directory
$saja->set_process_file('../myFunctionsDirectory/someOtherFile.php');

//the full path to some process file
$saja->set_process_file('/www/apache/htdocs/methods/someOtherFile.php');

//now call a function "someFunction" in the path set by set_process_file()
$saja->run("someFunction()");

Sometimes you may need to call a function that is in some other library, while all the other functions you are calling are in different libraries. In this case it is useful to be able to override the class-level default.

Override global and class-level process file


//call a function "someFunction" in the path set by the second parameter of run()
$saja->run("someFunction()", 'myDirectory/someOtherProcessFile.php');

Note that the process file location is never exposed to the end user. All process file paths (except for absolute paths) are relative to the location of saja.process.php.

Basic Output Responses - Where to Display the Results?

Now, we want to send all of these variables to a PHP function on the same server, and do something with the response of that function. To specify the output location, we can specify the output as follows:

ID:PROPERTY[,METHOD]

ID is any DOM element with an ID
PROPERTY is any valid property of the object, i.e. innerHTML, value, style, etc.
METHOD can be "p" for prepend, "a" for append, or left blank for replace (default)

So let's output the results of our function to the innerHTML of the DIV tag named "myDiv"

OUTPUT = myDiv:innerHTML

Now our entire SAJA script looks like this:

MyPHPFunction(inputText:value, myDiv:innerHTML, myId, 'ABC123', 12345)->myDiv:innerHTML

Any text (PHP errors included) generated by MyPHPFunction() will appear in the innerHTML of myDiv when this SAJA operation is called. This makes debugging your background PHP code just as easy as debugging your regular PHP code.

Embedding SAJA into your PHP document

Now that we have a nice SAJA command, we need to embed it in some HTML.

The saja command will most likely be executed during some javascript event such as ONCLICK.

On the PHP page which generates the HTML, we would embed SAJA as follows:

<div id="myDiv"></div>

<button onclick="<?=$saja->run("MyPHPFunction(inputText:value, 
myDiv:innerHTML, myId, 'ABC123', 12345)->myDiv:innerHTML;")?>">
Click to See what SAJA does
</button>

Notice the saja "run" method. This method simply takes in a SAJA script string, and converts it into the appropriate javascript output.

You can separate multiple SAJA commands via a semicolon if you would like to multithread calls to SAJA. Most browsers can support 2 simultaneous operations. The results of each call to SAJA will be returned independently.

Advanced Output Responses - Update Multiple Page Elements

The basic output response works great for updating simple text elements, or debugging your PHP scripts - but what if you want more than one event to occur upon the completion of your request? This is where the advanced response functionality comes into play.

These special methods will be called within your SAJA PHP functions, and are made available by using the "$this" keyword

The SAJA Resonse Methods

//Used to execute JavaScript callbacks or execute native JS functions.
$this->js("alert('all done!'); myCallBack('test', 123);");

//Place text inside of some element or property of an element.
$this->text('Text to place in some element','HtmlElementID[:Property]');

//Javascript Alert
$this->alert('Processing Complete!');

//Hide element with ID HtmlElementID
$this->hide('HtmlElementID');

//Show element with ID HtmlElementID
$this->show('HtmlElementID');

//Apply style string to an element with ID HtmlElementID
$this->style('HtmlElementID', 'color: #f00; font-weight: bold;');

//Redirect the user to some URL
$this->redirect('/home');

//Form Submission
$this->submit('form_name');

//Exit your PHP function and return all previous responses (optional)
return $this->send();

Whenever you use the advanced response methods, you will need to call return $this->send(); from inside of your function.

Using Browser History With Your AJAX Requests

Sometimes you might want the browser's "back" button to trigger an AJAX event, instead of taking the user off the current page. This is extremely useful when writing web applications like gmail. Imagine if the back button in gmail took you to the login page!

Although fairly simple, there are some concepts you need to understand before effectively using saja's history functionality.

This next concept is perhaps the most confusing, so please read this. Imagine you are on the saja demo page looking at the history section. You click "event one". A request is then sent to the php server, and returns the result "one". Now what happens when you click "back"? On the demo page, it sends another request which returns the original result "hello!". You, the user in fact triggered this "initializer" event without knowing it - otherwise, there would be no previous request to send, and hence we would never know that "hello" was originally there!

The initializer event is always passed into the saja_history() function as a regular saja command.

Enabling History With The Initializer Event

//Include this code near your page footer, or right before the </body> tag of your HTML document
<?=$saja->saja_history("ecco('hello!')->historyTest")?>

Again, you must think about this in terms of REQUESTS, and not CONTENT. In a case where multiple page elements are affected by browser history you will need much more complex logic to obtain results that make sense to the user. It is recommended that this feature be used in limited cases where a "back" button would make sense. In most cases, if you find this getting overly complex, you should avoid using ajax at all for that part of your application.

Adding a History-Enabled Ajax Event To Your Page

//same as a $saja->run request except with $saja->runWithHistory
<button onclick="<?=$saja->runWithHistory("ecco('one')->historyTest")?>">Event One</button>

Running an event in this manner tells SAJA to add the event to the history chain. The browser navigation buttons will then act to trigger this event whenever it is called in the history chain, just like a regular web page request.