Russian version
Add to Del.icio.us
English version
Digg It!

 Old-School dkLab | Constructor | JsHttpRequest 5: cross-browser AJAX + file uploading 

Site map :: Project Orphus :: Constructor


2006-07-29
Discuss at the Forum

You could also read the complete library documentation.

This article describes JsHttpRequest - an easy-to-use cross-browser AJAX library with AJAX file uploading support and many other features. JsHttpRequest first appeared as cross-browser analogue of XMLHttpRequest, and then became a very useful instrument to create dynamic web pages. It uses JavaScript (ActiveX, DOM, XMLHttpRequest if available) in frontend and PHP in backend.

Here is a short list of library's most interesting features and benefits.

  • Support and "transparent" work with any national character encoding (windows-1251, koi8-r and UTF-8 work even without iconv or mbstring).
  • AJAX file uploads.
  • Excellent cross-browser compatibility (e.g. works with IE 5.0 with disabled ActiveX).
  • Fully compatible with the popular JavaScript library prototype.
  • Full support of PHP debug features and coding traditions.
  • Multi-dimensional data structures exchange (associative arrays).
  • Automatic choice of the best AJAX realization (XMLHttpRequest, <SCRIPT>, <IFRAME>).
  • XMLHttpRequest-compatible interface is available.

Note that this article is a short turorial only. If you want more information, please view the following documents:

What is AJAX, backend and frontend?

AJAX (Asynchronous Javascript And XML), "Web 2.0" are technologies which assume more full usage of modern browsers' features (e.g. XMLHttpRequest and DOM). JsHttpRequest AJAX library allows, for example, making sub-queries to a web-server without page reload. You can request anything you want from a server and show it immediately on a dedicated page plock.

A good example of AJAX technology is Google Suggest (http://www.google.com/webhp?complete=1&hl=en):

The example of Google suggestions
Fig 1. Google Suggest. You type request and you get list of results immediately, without page reload.

Every AJAX web page consists of two parts: frontend and backend. In frontend you make queries to web pages and in backend you answer to a query.

The client's browser sends request to server, and gets an answer
Fig 2. Client-server structure of AJAX requests

For dummies 

Frontend is always run in a browser.
Backend is always run on your server.

In frontend we usually write the JavaScript code which passes data to a server, something like that: -

Listing 1: send a query
// Send a query.
JsHttpRequest.query(
  "/ajax/suggester",              // backend address
  { query: search_string.value }, // parameters
  function(result, errors) {
     // This function will be called when result is ready.
     // Suggest the most popular word as query.
     autocomplete_query(result["first"]["name"]);
     // Draw "suggestions" to query.
     show_suggestions (result);
  }
);

In backend we can use a PHP code to create an answer for the request. We will write something like the following:

Listing 2: proces a request
// Some functions that work with a database.
include "suggestions.lib.php";
// Get the query result.
$query = $_REQUEST["query"];
$result = get_suggestions($query);
// Give a name to the first element of result.
$result["first"] = $result[0];
$GLOBALS['_RESULT'] = $result; // $_RESULT will be passed to frontend

As you can see, there is nothing special in our code. The only thing is that we do not have query() method, and nothing sends the result back. But we do not need to write any more code ourselves, because JsHttpRequest comes out to the stage.

What does JsHttpRequest library offer?

JsHttpRequest AJAX library offers a very useful interface for writing both frontend and backend. You can see how it works just here, if you type something (e.g. "test") in the next field and wait 2 seconds or press Enter for immediate answer:

If you want to make a sub-query to server and you use JsHttpRequest, you will just need to call JsHttpRequest.query() method:

Listing 3: common library call
// Code for AJAX FRONTEND.
JsHttpRequest.query(
  address,                     // the path to backend
  data,                        // the JavaScript array with data you want to pass
  onreadyfunc(result, errors), // the function is called when an answer is ready
  nocache                      // if set to TRUE, caching will be disabled
);

As you can see, there is nothing unnecessary in this function, we will always need to specify the path to backend (we can have several backends), we will always pass some data to server, and we will always react to the answer of server. Note that we do not use anything dependent on user's browser.

To send a file via AJAX, you will need to:

  • create <form enctype="multipart/form-data">;
  • place there <input type="file" ... id="somefile">;
  • pass a DOM node of the file field as value (instead of string, array or integer);
  • use something like { somefile: document.getElementById("somefile"); }.

(See example below for details.)

In backend you get data from $_REQUEST or $_FILES array and put an answer to $_RESULT array.

JsHttpRequest converts JavaScript array data to PHP array $_REQUEST with the help of PHP itself ($_REQUEST is a standard array of input data used in non-AJAX scripts). It also puts the required information about uploaded files to $_FILES array, so you can use the standard mechanism of PHP file uploads.

Lyrical deviation 
You can freely pass multidimensional arrays from backend and to backend.

JsHttpRequest usage example

So, let's see some examples! We're going to write a fully-working AJAX application, which calculates MD5 of the entered string or the content of a selected file. We will use JsHttpRequest, of course.

For dummies 

MD5 is a popular cryptographical function, which returns unique identifier for any passed string data. It guarantees that this identifier will be different rather if two strings are quate large and differs in a couple of character. (More exact, a match probability is very-very small.) We can compare MD5 with human fingerprints: you cannot find two men with absolutely equal fingerprints.

FRONTEND (md5_frontend.htm)

Listing 4: test/JsHttpRequest/md5_frontend.htm
<script src="../../lib/JsHttpRequest/JsHttpRequest.js"></script>
<script language="JavaScript">
    // Function is called when we need to calculate MD5.
    function calculate_md5() {
        JsHttpRequest.query(
            'md5_backend.php', // backend
            {
                // pass a text value 
                'str': document.getElementById("mystr").value,  
                // path a file to be uploaded
                'upl': document.getElementById("myupl")
            },
            // Function is called when an answer arrives. 
            function(result, errors) {
                // Write errors to the debug div.
                document.getElementById("debug").innerHTML = errors; 
                // Write the answer.
                if (result) {
                    document.getElementById("ans").innerHTML = 
                        'MD5("' + result["str"] + '") = ' + result["md5"];
                }
            },
            false  // do not disable caching
        );
    }
</script>

<!-- Please note that we must specify enctype to multipart/form-data! -->
<form method="post" enctype="multipart/form-data" onsubmit="return false">
    Enter a text: <input type="text" id="mystr"><br>
    ...or upload a file: <input type="file" id="myupl"><br>
    <input type="button" value="Calculate MD5" onclick="calculate_md5()">
</form>

<div id="ans" style="border:1px solid #000; padding:2px">
    Structured results
</div>
<div id="debug" style="border:1px dashed red; padding:2px">
    Debug info
</div>

Don't be afraid of the size of frontend, we just cannot make it smaller as we write a fully-working application.

For dummies 

Associative arrays in JavaScript can be created using the following syntax:
my_js_array = { key1: value1, key2: value2, ... }
You can access properties either writing my_js_array.key1 or my_js_array["key1"].

You may also watch the work of this frontend online at here.

BACKEND (md5_backend.php)

Listing 5: test/JsHttpRequest/md5_backend.php
<?php
require_once "../../lib/JsHttpRequest/JsHttpRequest.php";
// Init JsHttpRequest and specify the encoding. It's important!
$JsHttpRequest =& new JsHttpRequest("windows-1251");
// Fetch request parameters.
$str = $_REQUEST['str'];
$upl = @$_FILES['upl'];
// Create the resulting array.
if (@$upl['tmp_name']) {
    // The file was successfully uploaded.
    $GLOBALS['_RESULT'] = array(
      "str"   => 'file ' . $upl['name'],
      "md5"   => md5(file_get_contents($upl['tmp_name'])),
    );
} else {
    // No file is uploaded, use the plain string.
    $GLOBALS['_RESULT'] = array(
      "str"   => $str,
      "md5"   => md5($str),
    );
}
// Everything we print will go to 'errors' parameter.
echo "<pre>";
?>
<b>QUERY_STRING:</b> <?=$_SERVER['QUERY_STRING'] . "\n"?>
<b>Uploaded files:</b> <?=print_r($_FILES, 1)?>
<?php
echo "</pre>";
// This includes a PHP fatal error! It will go to the debug stream,
// frontend may intercept this and act a reaction.
if ($_REQUEST['str'] == 'error') {
  error_demonstration__make_a_mistake_calling_undefined_function();
}
?>

You could have expected that our backend would be very large, but is not true! In backend we should not care about the way our information is displayed in browser: it is the task of a frontend.

You may download an archive demo.zip with all of the source code above, unpack it anywhere on your site and open http://your-site/path-to-demo/test/JsHttpRequest/md5_frontend.htm in your Web browser. (All samples are at the directory test/JsHttpRequest inside the downloaded archive.)

Work together with the Prototype library

Prototype is a very popular tool to simplify a JavaScript programmer's work. It includes AJAX support and other features. Library JsHttpRequest could be used as its server part in PHP (after inclusion of a small compatibility module JsHttpRequest-prototype.js). Even so, all additional features of JsHttpRequest (cross-browser compatibility, file uploading support, work with national charsets etc.) are still available.

Listing 6: Use typical Prototype functions
<script src="../../lib/JsHttpRequest/JsHttpRequest.js"></script>
<script src="../../lib/JsHttpRequest/JsHttpRequest-prototype.js></script>
<script language="JavaScript">
new Ajax.Request('your_ajax_script.php', {
  method: 'get',
  parameters: {
    name: 'Dmitry',  
    file: $("my_upload_file")
  },
  onFailure: function(tr) {
    alert('Error code: ' + tr.status + '\n');
    alert(tr.responseText);
  },
  onSuccess: function(tr) {
    $("result").innerHTML = tr.responseJS.hello; 
    if (tr.responseText) alert(tr.responseText);
  }
});
</script>

Of course you could use any other capabilities of the prototype for AJAX (e.g. functions for dynamic data loading into a HTML element).

Conclusion

Now you know that it is very easy to work with AJAX using JsHttpRequest. To know what else can you do with JsHttpRequest library, consider reading the following documents:

The JsHttpRequest library author thanks Yuri Nasretdinov for the first version of this article.





Dmitry Koterov, Dk lab. ©1999-2014
GZip
Add to Del.icio.us   Digg It!   Reddit