Adventure,PHP,framework,page controller,front controller,pattern,object orientated design,software,development,reusability,uml,tutorial,benchmark,brilliant performance,

Search:    
Downloads  |  SVN!  |  Roadmap  |  Forum!  |  Bugtracking  |  Guestbook  |  Backlinks!  |  References!  |  Sitemap  |  Impress  
 
English Adventure PHP Framework  Bookmark @ Technorati Bookmark @ del.icio.us Bookmark @ Mr. Wong Bookmark @ Simpy Bookmark @ Google Bookmark @ Digg.com Adventure PHP Framework Print page 061-AJAX-and-the-APF

AJAX & the adventure php framework

Article summary I
Encoded slashes lead to 404 error!

Using a front controller action as a server side component, encoded slashes and backslashes lead to a 404 error if the "AllowEncodedSlashes = On" is not set in your VHOST configuration.
>

1. Introduction

AJAX is noted for beeing a common technique to build web applications, that are more agile compared to standard applications. It gives the possibility to change specific parts of the DOM of a HTML page by using the XMLHTTPRequest implementation and some lines of java script code.

AJAX is not brand-new and there are a plenty of online arcticles about building AJAX applications. At a glance, the following resources are worth being read:
Rank article:
This article has not yet been ranked. Vote this article first of all!
Starting to write AJAX applications you will face with the problem to integrate AJAX widgets and dynamic updates of certain areas of your web page into existing application structures and designs. This fact often leads to the problem, that AJAX-featured applications tend to be not well-designed. Im most cases, the client <-> server communication is done by requesting a file (e.g. a PHP file), that sends back an XML string containing the information the client needs. In common for each AJAX "action" one appropriate file is created. This does not only lead to complexity but also to redundant code in the server side scripts. A second problem is security. Due to the fact, that the application code merely resides on the client and hence can be analysed and manipulated easily, an application tends to get insecure.

The two problems described above are well known problems. On this account many server and cliend side AJAX frameworks have been built to solve the daily life problems a programmer is facing during AJAX application development. However, building AJAX aplications is not as easy as it is described in many of those "getting started" tutorials.


2. Which tools are included in the APF?

Basically the adventure php framework features no special AJAX component to use either on the client or on the server side. Having no special module does not mean, that the APF does not have a way to facilitate server side programming within AJAX applications.

To assist implementation of server side AJAX application parts, the front controller can be used. Taking the front controller supports the programmer to build server side AJAX "actions" in a standardized and powerful way. He is not forced to create several action files and reimplement the functionality included in those files several times. Each AJAX action can be represented by one special front controller action. Due to the fact that the front controller pattern is located in the business layer, the front controller action can easily use existing application components (e.g. business or data layer classes). Moreover using the front controller makes it easy to access the parameters the action is called with. In other words, all modules known for building server side applications can be involved.

Due to a wide range of java sctip AJAX frameworks the adventure php framework features no java script libraries. For client side purpose any common AJAX framework can be used to create the desired widgets. The following list shows a selection of famous java script frameworks:

3. My first AJAX application

To not getting you bored with theory, this chapter shows you, how to build a AJAX web application with the adventure php framework from the scratch.

3.1. Requirements and considerations

Due to the fact, that we both are good software architects, we need to think about the requirements of the software, we want to create. To keep things simple, the application to design should be simple and easy to imagine. I think a news box would be a good example to show how an AJAX application can be built with the adventure php framework.

Let me give you a brief description of the major features:
  • news box can be included in any adventure php framework application
  • news can be paged clockwise and vice versa
  • news are read from several text files, each containing one news page, to keep maintenance easy

3.2. Design of the application

Compared to a standard application only the paging functionality is realized in AJAX style. The rest of the module can be implemented as customary. The concepts used here (commonly known as patterns) can be comprehended reading the comment function tutorial. But the focus of this article lies on the design of the AJAX part of the application.

In order to implement the paging functionality we need client and server addons. On the cliend side we will use some java script code around the XMLHTTPRequest object to draw the widgets and to catch user interaction. The server side is done by a special front controller action, that reads the desired news page and gives it back to the client.


4. Implementation

To make sure, that the news box can be included in any APF style application we create a new module named newspager. In the first instance, the folders and files must be created as follows:
  /apps/
        modules/
                newspager/
                          biz/
                              actions/
                          data/
                          pres/
                               documentcontroller/
                               templates/
As a next step, the files necessary must be created. As already mentioned above, we need to create the following files:
  • biz/newspagerManager.php:
    business component, that is used to get the news page content
  • biz/newspagerContent.php:
    the domain object, that contains the content of one news page
  • biz/actions/newspagerAction.php:
    file that contains the front controller action class
  • biz/actions/newspagerInput.php:
    file that contains the front controller input class
  • data/newspagerMapper.php:
    data layer component, that loads the newspager content from text files
  • pres/documentcontroller/newspager_v1_controller.php:
    document controller, that generates the output of the module
  • pres/templates/newspager.html:
    template file, that contains the style of the module and the additional java script code needed to add AJAX style paging

In this tutorial we are going to use the bottom-up approch during implementation phase.


4.1. Data layer implementation

The data layer's duty is to load content from plain text files, map a news file into a domain object and give it back to the business layer. The news files are located in the ./frontend/news/ folder located in parallel to the index.php file of a project. Each file contains news text in a certain semantic: the first line is interpreted as the headline, the second as a subheadline and the rest of the file is assumed to belong to the content. On this account the domain object mentioned above has three properties: title, subtitle and content. To have multilanguage support, each file should be named like
  news_{LANG}_{PAGENUMBER}.txt
Here {LANG} must be any two letter ISO language code, {PAGENUMBER} is a number beginning with 1. As an example, the news pager module can have the following news files located in ./frontend/news/:
  news_en_1.txt
  news_en_2.txt
  news_en_3.txt
  news_en_4.txt
  news_en_5.txt
  news_it_1.txt
  news_it_2.txt
  news_it_3.txt
  news_it_4.txt
The source code of the data layer class can be seen in the code box below:
import('modules::newspager::biz','newspagerContent');
import('core::filesystem','filesystemHandler');

class 
newspagerMapper extends coreObject
{

   
/**
   *  @private
   *  Defines the dir, where the news content is located.
   */
   
var $__DataDir null;


   function 
newspagerMapper(){
   }

   function 
init($DataDir){
      
$this->__DataDir $DataDir;
    
// end function
   
}

   function 
getNewsByPage($PageNumber){

      
// create filesystem handler
      
$fM = new filesystemHandler($this->__DataDir);

      
// read all files located there
      
$RawFiles $fM->showDirContent();

      
// get files, that match the current language
      
$Files = array();
      
$count count($RawFiles);

      for(
$i 0$i $count$i++){

         if(
substr_count($RawFiles[$i],'news_'.$this->__Language.'_') > 0){
            
$Files[] = $RawFiles[$i];
          
// end if
         
}

       
// end for
      
}

      
// throw error when page count is zero!
      
$NewsCount count($Files);

      if(
$NewsCount == 0){
         
trigger_error('[newspagerMapper::getNewsByPage()] No news files are given for language '.$this->__Language,E_USER_ERROR);
         exit;
       
// end if
      
}

      
// if page number is lower then zero, correct it!
      
if($PageNumber <= 0){
         
$PageNumber 1;
       
// end if
      
}

      
// if page number is higher then max, correct it!
      
if($PageNumber $NewsCount){
         
$PageNumber $NewsCount;
       
// end if
      
}

      
// read content of file
      
$NewsArray file($this->__DataDir.'/'.$Files[$PageNumber 1]);

      
// initialize a new news content object
      
$N = new newspagerContent();

      
// fill headline
      
if(isset($NewsArray[0])){
         
$N->set('Headline',trim($NewsArray[0]));
       
// end if
      
}

      
// fill subheadline
      
if(isset($NewsArray[1])){
         
$N->set('Subheadline',trim($NewsArray[1]));
       
// end if
      
}

      
// fill content
      
$count count($NewsArray);
      if(
$count >= 3){
         
$Content = (string)'';
         for(
$i 2$i $count$i++){
            
$Content .= $NewsArray[$i];
          
// end for
         
}
         
$N->set('Content',trim($Content));

       
// end if
      
}

      
// set news count
      
$N->set('NewsCount',$NewsCount);

      
// return object
      
return $N;

    
// end function
   
}

 
// end class
Calling the mapper class like
   $M = new newspagerMapper();
   
$M->set('Context','sites::apfdocupage');
   
$M->set('Language','en');
   echo 
printObject($M->getNewsByPage(1)); 
is will return an newspagerContent object, that contains the information of the first news page residing in the news_en_1.txt file. This object can later on be used to deliver the xml requested by the java script code executed on the client machine or to generate the output of the news box during rendering of the page.


4.2. Business layer implementation

4.2.1. Domain object
First of all, we must define the newspagerContent class, that was already used in the data layer component. This class is a simple data storage class, that contains the information of a certain news page. Due to the fact, that this class inherits from coreObject no more get() and set() methods must be implemented. The source code looks like this:
class newspagerContent extends coreObject
{

   
/**
   *  @private
   *  Headline of a news page.
   */
   
var $__Headline;


   
/**
   *  @private
   *  Subheadline of a news page.
   */
   
var $__Subheadline;


   
/**
   *  @private
   *  Content of a news page.
   */
   
var $__Content;


   
/**
   *  @private
   *  Number of news pages.
   */
   
var $__NewsCount;


   function 
newspagerContent(){
   }

 
// end class
The attribute $__NewsCount was introduced to control the pager widgets.


4.2.2. The manager
To be compilant to the classical thee tier architecture described in the pattern of the same name, we introduce a business component, that contains the business logic of the application. In this case the business layer component (often called manager) only contains of one singe method: getNewsByPage(). The implementation is quite easy and so the php code looks as follows:
import('modules::newspager::data','newspagerMapper');

class 
newspagerManager extends coreObject
{

   
/**
   *  @private
   *  Defines the dir, where the news content is located.
   */
   
var $__DataDir null;


   function 
newspagerManager(){
   }

   function 
init($DataDir){

      
// cut trailing slash if necessary
      
if(substr($DataDir,strlen($DataDir) - 1) == '/'){
         
$this->__DataDir substr($DataDir,0,strlen($DataDir) -1);
       
// end if
      
}
      else{
         
$this->__DataDir $DataDir;
       
// end else
      
}

    
// end function
   
}

   function 
getNewsByPage($PageNumber 1){

      
// get mapper
      
$nM = &$this->__getAndInitServiceObject('modules::newspager::data','newspagerMapper',$this->__DataDir);

      
// load and return news object
      
return $nM->getNewsByPage($PageNumber);

    
// end function
   
}

 
// end class
A unit test for the class and the underlaying data layer may look like this:
  $M = new newspagerManager();
  
$M->set('Context','sites::apfdocupage');
  
$M->set('Language','en');
  echo 
printObject($M->getNewsByPage()); 
This statement will print out the content of the loaded newspagerContent object.


4.2.3. AJAX data source
As mentioned above, the client side java script codes needs a server side data source to obtain the desired news page via xml. For this reason a front controller action is implemented, that delivers the desired page. Due to the fact, that we have a business layer component (manager), the action can make use of this class. The only task is then to transform the object returned by the business layer component into valid xml and transfer it to the client machine. To indicate, which page should be served, the front controller action url string does contains the parameter page. Adventure php framework front controller actions normally contain three main parts: the action class definition, the input class definition and the action configuration that defines the parameters of the front controller action. Details can be seen on the front controller page. Because this example has no special requirements, the implementation is straight forward.

First of all, we have to implement the input object, that is filled with the url parameters present in the url string when requesting the action. The class must inherit from the FrontcontrollerInput class and the file only contains the following body:
class newspagerInput extends FrontcontrollerInput
{

   function 
newspagerInput(){
   }

 
// end class
The action class definition encapsulates the functionality described a few lines above. As described on the front controller page, each action must implement the interface method run(), that is called during action execution by the front controller. This function includes the main capacity and delivers the xml string to the requestor. The source code may look like follows:
import('modules::newspager::biz','newspagerManager');

class 
newspagerAction extends AbstractFrontcontrollerAction
{

   function 
newspagerAction(){
   }

   function 
run(){

      
// get desired page number, language and data dir
      
$Page $this->__Input->getAttribute('page');
      
$Language $this->__Input->getAttribute('lang');
      
$DataDir base64_decode($this->__Input->getAttribute('datadir'));

      
// get manager
      
$nM = &$this->__getAndInitServiceObject('modules::newspager::data','newspagerManager',$DataDir);

      
// set language
      
$nM->set('Language',$Language);

      
// load news object
      
$N $nM->getNewsByPage($Page);

      
// create xml
      
$XML = (string)'';
      
$XML .= '<?xml version="1.0" encoding="utf-8" ?>';
      
$XML .= '<news>';
      
$XML .= '<headline>'.$N->get('Headline').'</headline>';
      
$XML .= '<subheadline>'.$N->get('Subheadline').'</subheadline>';
      
$XML .= '<content>'.$N->get('Content').'</content>';
      
$XML .= '<newscount>'.$N->get('NewsCount').'</newscount>';
      
$XML .= '</news>';

      
// send xml
      
header('Content-Type: text/xml; charset=iso-8859-1');
      echo 
$XML;

      
// close application
      
exit(0);

    
// end function
   
}

 
// end class
To be able to write a unit test, or to call the action, the third part of an APF style front controller action must be added: the configuration. To create this file, we must define, under which namespace the action should be callable. For this example, we assume, that the action can be executed using the url definition
http://dev.adventure-php-framework.org/~/modules_newspager_biz-action/Pager/page/1/lang/en
 /~/modules_newspager_biz-action/Pager/page/{PAGE}/lang/{LANG}
where {PAGE} must be replaced by any integer and LANG a two letter ISO language code. Hence, the namespace of the action is modules::newspager::biz and though the configuration file for this action must be created under the folder
 /apps/config/modules/newspager/biz/actions/{APPS__CONTEXT}/
Thereby {APPS__CONTEXT} is the folder path resulting from the current context of the application. In this example, the context is sites::demosite, and consequently, the full path must be
 /apps/config/modules/newspager/biz/actions/sites/demosite/
The config file itself must be named
 DEFAULT_actionconfig.ini
because the current environment variable is set to DEFAULT. In common, the action definition file contains the following lines:
[Pager]
FC.ActionNamespace = "modules::newspager::biz::actions"
FC.ActionFile = "newspagerAction"
FC.ActionClass = "newspagerAction"
FC.InputFile = "newspagerInput"
FC.InputClass = "newspagerInput"
FC.InputParams = ""
As described on the front controller page, the section name corresponds to the action name, the section itself defines which files contain the action and input classes. The sixth parameter can be used to specify standard parameters for the input object.

Calling the url
  /~/modules_newspager_biz-action/Pager/page/1/lang/en
will display a XML similar to that:
  <news>
    <headline>APF news</headline>
    <subheadline>New version 1.5 available!</subheadline>
    <content>
      We are proud to present the new version 1.5 of the adventure php framework. It includes
      bugfixes and enhancements of the front controller component and a complete review of the
      documentation plus translation of the entire documentation chapters into english language.
    </content>
    <newscount>4</newscount>
 </news>

4.3. Presentation layer implementation

The presentation layer faces two main issues: create the news box on page creation and provide the necessary java script code to update the news box in AJAX style. Sensibly, we first deal with the generation of the news box, because this can be done with standard adventure php framework appliances. Due to the fact, that the news box is created through dynamically generated content (here: text files), we need a document controller and a template file. The template file defines the structure of the box according to the MVC pattern and the document controller generates the view content using the template file definition.


4.3.1. The template file
Due to the fact, that we have to display a box with three values filled in it, the template file looks as follows:
<@controller
               namespace="modules::newspager::pres::documentcontroller"
               file="newspager_v1_controller"
               class="newspager_v1_controller"
@>
<div style="width: 300px; float: right; border: 1px dashed #777BB4; margin: 10px;">
  <table cellpadding="0" cellspacing="0">
    <tr>
      <td style="text-align: center; vertical-align: center; width: 15px; background-color: #777BB4; font-size: 16px;">
        <span style="font-weight: bold;">&lt;</span>
      </td>
      <td style="width: 270px; height: 80px; padding: 2px; vertical-align: top; text-align: left;">
        <span style="font-variant: small-caps; font-size: 16px; font-weight: bold;">
          <html:placeholder name="Headline" />
        </span>
        <br />
        <span style="font-size: 12px; font-style: italic;"><html:placeholder name="Subheadline" /></span>
        <br />
        <br />
        <span style="font-size: 11px;"><html:placeholder name="Content" /></span>
      </td>
      <td style="text-align: center; vertical-align: center; width: 15px; background-color: #777BB4; font-size: 16px;">
        <span style="font-weight: bold;">&gt;</span>
      </td>
    </tr>
  </table>
</div>
As the html code box shows, the template file contains a document controller specification and three place holders to be filled with the content of the domain object.


4.3.2. The document controller
The corresponding document controller loads the newspagerContent object and filles the place holders:
import('modules::newspager::biz','newspagerManager');

class 
newspager_v1_controller extends baseController
{

   function 
newspager_v1_controller(){
   }

   function 
transformContent(){

      
// get manager
      
$nM = &$this->__getServiceObject('modules::newspager::data','newspagerManager');

      
// load default news page
      
$N $nM->getNewsByPage();

      
// fill place holders
      
$this->setPlaceHolder('Headline',$N->get('Headline'));
      
$this->setPlaceHolder('Subheadline',$N->get('Subheadline'));
      
$this->setPlaceHolder('Content',$N->get('Content'));

    
// end function
   
}

 
// end class

4.3.3. The AJAX java script code
To add dynamic paging to the news box, some java script code must be added. Therefore, we add a
  <script type="text/javascript">
  </script>
to the newspager.html template file. As we have learned above, the XMLHTTPRequest object is used to send a request via java script to retrieve dynamic information from a server script to update a page part without reloading the page. For this reason we use the following java script function to create an instance of the XMLHTTPRequest object:
   function createXMLHttpRequest(){

     if(window.ActiveXObject){

          try{
             // IE 6 and higher
             xhttp = new ActiveXObject("MSXML2.XMLHTTP");
           // end try
          }
          catch (e){

              try{
                 // IE 5
                 xhttp = new ActiveXObject("Microsoft.XMLHTTP");
               // end try
              }
              catch (e){
                 xhttp = false;
               // end catch
              }

           // end catch
          }

       // end if
      }
      else if(window.XMLHttpRequest){

          try{
             // Mozilla, Opera, Safari ...
             xhttp = new XMLHttpRequest();
           // end try
          }
          catch (e){
             xhttp = false;
           // end catch
          }

       // end else if
      }

    // end function
   }

   // execute createXMLHttpRequest() on window load
   window.onload = createXMLHttpRequest;
The window.onload tells the browser to execute the createXMLHttpRequest after having loaded the page. In order to be able to manipulate the content of the page, we have to upgrade the template definition with ids for each tag. So we can access each tag by using the
   var dom_node = document.getElementById('dom_node_id');
construct. Moreover, we must add an event handler to the two pager signs, so that the content of the box can be changed. Therefore I defined two different java script functions (prev() and next()), that wrap the functionality of getting forward or backward. Te next code box shows the changes, we have to apply to the html code of the template file:
<div style="width: 300px; float: right; border: 1px dashed #777BB4; margin: 10px;">
  <table cellpadding="0" cellspacing="0">
    <tr>
      <td style="text-align: center; vertical-align: center; width: 15px; background-color: #777BB4; font-size: 16px;">
        <span id="newspager_prev_button" style="font-weight: bold; cursor: pointer; visibility: hidden;" onclick="prev();">
          &lt;
        </span>
      </td>
      <td style="width: 270px; height: 80px; padding: 2px; vertical-align: top; text-align: left;">
        <span id="newspager_headline" style="font-variant: small-caps; font-size: 16px; font-weight: bold;">
          <html:placeholder name="Headline" />
        </span>
        <br />
        <span id="newspager_subheadline" style="font-size: 12px; font-style: italic;">
          <html:placeholder name="Subheadline" />
        </span>
        <br />
        <br />
        <span id="newspager_content" style="font-size: 11px;"><html:placeholder name="Content" /></span>
      </td>
      <td style="text-align: center; vertical-align: center; width: 15px; background-color: #777BB4; font-size: 16px;">
        <span id="newspager_next_button" style="font-weight: bold; cursor: pointer;" onclick="next();">
          &gt;
        </span>
      </td>
    </tr>
  </table>
</div>
The functions mentioned above contain the following lines:
   function next(){

      // check if XMLHTTPRequest object is initialized correctly
      if(!xhttp){
         alert("An Error occured when trying to initialize the XMLHttpRequest object!");
         return;
       // end if
      }

      // increment page number
      pagenumber = pagenumber + 1;

      // create request
      var request = "/~/modules_newspager_biz-action/Pager/page/" + pagenumber + "/lang/" + language;

      // send request for next news
      xhttp.open("GET",request,true);
      xhttp.onreadystatechange = updateNewsContent;
      xhttp.send(null);

    // end function
   }

   function prev(){

      // check if XMLHTTPRequest object is initialized correctly
      if(!xhttp){
         alert("An Error occured when trying to initialize the XMLHttpRequest object!");
         return;
       // end if
      }

      // decrement page number
      pagenumber = pagenumber - 1;

      // create request
      var request = "/~/modules_newspager_biz-action/Pager/page/" + pagenumber + "/lang/" + language;

      // send request for next or prev news page
      xhttp.open("GET",request,true);
      xhttp.onreadystatechange = updateNewsContent;
      xhttp.send(null);

    // end function
   }
First of all, each function checks, wheather the XMLHTTPRequest object was created successfully. Second, the page number is either incremented or decremented to indicate the page number to load. After that, the front controller style request is constructed. Due to the fact, that xml http requests only can be done for the same domain, the page is delivered, we can define the url string relatively. The last code block then opens the defined url for a GET request, defines a event handler for the readystatechange event and sends the request.

Some of you now may say, that the function definition should be more generic. The answer is: yes, it may. But this example is there to demonstrate the way of how you can add AJAX support to your application. As this module is quite simple, complexity drastically raises, when implementing more substantial applications.

Let's now discuss the event handler function for updating the content view of the news box. This method has two main tasks to execute: display the content of the XMLHTTPRequest request and control the pager arrows, when the maximum or minimum number of pages has been reached. To do so, we have to create the following java script code:
   function updateNewsContent() {

      // check for ready loadad and HTTP status 200 (OK)
      if(xhttp.readyState == 4 && xhttp.status == 200){

         // get request xml
         var responseXML = xhttp.responseXML;

         // insert xml values into the desired spans
         var headline = responseXML.getElementsByTagName('news').item(0).childNodes[0].textContent;
         document.getElementById("newspager_headline").innerHTML = headline;

         var subheadline = responseXML.getElementsByTagName('news').item(0).childNodes[1].textContent;
         document.getElementById("newspager_subheadline").innerHTML = subheadline;

         var content = responseXML.getElementsByTagName('news').item(0).childNodes[2].textContent;
         document.getElementById("newspager_content").innerHTML = content;

         // extract news count out of the xml
         var newscount = responseXML.getElementsByTagName('news').item(0).childNodes[3].textContent;

         // enable prev and next button by default
         document.getElementById("newspager_prev_button").style.visibility = "visible";
         document.getElementById("newspager_next_button").style.visibility = "visible";

         // disable next button if desired
         if(pagenumber >= newscount){
            document.getElementById("newspager_next_button").style.visibility = "hidden";
          // end if
         }

         // disable prev button if desired
         if(pagenumber <= 1){
            document.getElementById("newspager_prev_button").style.visibility = "hidden";
            pagenumber = 1;
          // end if
         }

       // end if
      }
As you can see in line 4, the function waits for the request being completed. If this is the case, the content of the request is read from the xhttp object created before. The responseXML attribute contains a DOM document, that can be accessed via java script functions. The second code block updates the spans addressed by the given DOM ids. To be able to control the pager buttons, we have to know the maximum number of pages and the current page number. For this reason the news count is initially filled and is included in each response. The initialisation of the newscount value is simply done by adding the declaration block
   // declare variable to be initialized with the XMLHttpRequest object
   var xhttp;

   // declare current page number
   var pagenumber = 1;

   // declace news count
   var newscount = <html:placeholder name="NewsCount" />;

   // declare current language
   var language = "<html:placeholder name="NewsLanguage" />";
to the java script code and fill the place holders by append the following php code to the document controller:
   $this->setPlaceHolder('NewsLanguage',$this->__Language);
   
$this->setPlaceHolder('NewsCount',$N->get('NewsCount')); 

5. Lessons learned

This chapter is intended to list the pitfalls, that can appear during AJAX application development.
  • Apache answers request with a 404 error page:
    If you write any application, that saves data in your data base using an AJAX request, it is recommended to encode your form data using the encodeURIComponent() function. Doing so, also slashes and backslashes are encoded. If your server side AJAX component is a front controller action, that is requested by a url rewrited url string, having encoded slashes or backslashes will result in a 404 error code. The problem is, that the apache webserver decodes the slashes and thus creates a wrong url.

    The solution is quite easy: you just have to add the directive
    AllowEncodedSlashes On
    to your VHOST configuration. This apache bug cost me three days to find!

  • Degugging tools:
    Unfortunately only the firefox browser contains a powerful debugging and analyzing tool (firebug), that really helps tracing your application. Opera features a firefox-like toolbar, but the functionality is less. For the internet explorer I have not found any equivalent product to be able to see the browser objects (especially the content of the xhttp variable). The IE toolbar only has a DOM tree browser and some other useful features.

    Due to this fact, I was not able to get the news box application running on IE browsers. Perhaps someone could give me advive. Please refer to the following thread, that contains a description: http://www.phpfriend.de/forum/ftopic63486.html.

  • Character encoding issues:
    As I mentioned during tests with user input data, firefox and opera send data in UTF-8 format to the server although the page is delivered in ISO-8859-1 encoding. This leads to the problem, that data, that is sent back to the browser is encoded with the wrong character set. To solve this, the data must be translated into the target charset using utf8_decode().

  • Implementation review:
    In my opinion it is much more complex to build AJAX applications from the scratch, because you are forced to implement all the features you have included in a server side php framework like the adventure php framework once more. Otherwise you are getting crazy with all that
    document.getElementById()
    or
    foo.innerHTML = bar
    So adding AJAX features to your application means, that you have to think very carefully about your application or module design. I even claim, that writing AJAX applications needs much more understanding of good application design. Otherwise, this leads to bad software architecture!


Comments

Do you want to add a comment to the article above, or do you want to post additional hints? So please click here. Comments already posted can be found below.


There are no comments belonging to this article.


Powered by WebRing.