Sunday, February 5, 2012

HTML5 series part 2: IndexedDB


In the previous article, we explored localstorage(DOM Storage) API. One of the coolest features of local storage is that it is damn simple to use. basically you are dealing with bunch of getter and setter methods to get the benefit of localstorage. Its actually scaled up version of cookies. But the limitations are quite obvious when we need to operate on relatively large amount data. 
firstly,  values are unstructured in localstorage. searching and filtering will be on the order of O(n).
secondly, everything is string here. you cannot store objects unless you are using JSON.stringify and JSON.parse. both SQL and recently popular NoSQL based solutions were proposed. the solutions came in the form of web SQL database and IndexedDB respectively. 

web SQL database:

SQL based web SQL database didn't get wide acceptance among the browser developers. Though browsers like Chrome, Safari and Opera supported web SQL database but popular browser Firefox was more interested in NoSQL based IndexedDB. as a result Firefox doesn't even have minimal support for web SQL database. Finally, W3C wrote the death certificate of web SQL database API by keeping it off active maintenance. they cited lack of independent implementations as being the reason because most of the browser relied on SQLite as the underlying database. web SQL database brought real relational database implementation on browsers.  data could be stored in a very structured way. it supported JOIN operation to give quick access.

IndexedDB:

It looks like IndexedDB is going to be the standard for large scale storage in client. Structurally IndexedDB sits somewhere between true SQL and unstructured localStorage systm. basic features include:
    1. values are stored in javascript objects
    2. quick search and filtering is supported by separate indexing system.
    3. both synchronous and asynchronous APIs are available in the specification (Though no browser   
        yet implemented synchronous API). But for the time being, its mostly anynchronous
   4.  Joining is also possible. 
   5.  object-oriented.
   6.  based on transactional database model. every operation is executed in a particular context of 
        transaction (Three types of transactions: read/write transactions, read only and snapshot). this     
        comes handy when you open two instances of same web application in two different browser tabs. 
   7. data stored as key-value pairs.
   8. uses DOM based event system to notify when result is ready for an operation (typical for    
        asynchronous paradigm)
   9. Like AJAX, IndexedDB obeys same origin policy to enforce data security. each origin ( or 
       website) has its own set of databases that are not allowed to accessing data of database sets loaded 
      a different domain or website. origin is differentiated using the combination of protocol, domain      
      name   and port number.  http://www.example.com and http://www.example.com/en/  both have same origin but  https://www.example.com and  http://www.example.com spawned from two different origin. (differs in protocol)

Synchronous API:

HTML5 supports Concurrency through worker API. Synchronous API of IndexedDB is intended to be used with Worker API. 

Asynchronous API:
       
everything is asynchronous here. you need to make sure to wrap the codes that depends on the query result, in a callback function. every operation must have callback functions that will be executed in response to the event fired as a result of the operation. 

Object Stores:

Every database is named and contains one or more named Object Stores. Object stores can be grossly compared to tables in relational database parlance. every stored object must contain(explicitly or implicitly) any properties  defined by Object Stores . values stored in Object Store are structured and doesn't have rigidly defined schema. Object Store can contain one or more Indexes for easy filtering .

Cross-browser API instances:

Because of the difference in the implementation across vendors, obtaining instance is a bit different vendor-wise.
if("webkitIndexedDB" in window){
       window.indexedDB = window.webkitIndexedDB;
       window.IDBTransaction = window.webkitIDBTransaction;
       window.IDBKeyRange = window.webkitIDBKeyRange;
}else if("moz_indexedDB" in window){
       window.indexedDB = window.moz_indexedDB;
}
if(!window.indexedDB){
     alert("browser doesn't support indexedDB.");
}

why not simple namespacing:

var exampledb = {};
exampledb.indexedDB = {};


Database creation is asynchronous:

exampledb.indexedDB.open = function(){
     var result = window.indexedDB.open(
         "mydb",   // database name/ID
         "my sample db" // tiny description
     );
     result.onsuccess = functnion(e) {
         // the result attribute of the event, e holds the reference to database
          exampledb.indexedDB.db = e.target.result;
         ..... // do as needed.
     };
     result.onerror = function(e){ 
          .... 
      };
}


Database can be versioned and its asynchronous too:
      
result.onsuccess = functnion(e) {
   // the result attribute of the event, e holds the reference to database
    exampledb.indexedDB.db = e.target.result;
    var db = exampledb.indexedDB.db;
    if("" == db.version){
           // user is visiting the page for the first time. lets setup database 
           // by creating 
           // necessary Object Stores and populating default data.
           var setVrequest = db.setVersion("1.0");
            // setting a version creates an implicit transaction which ensures 
            // everything in the callback
            // succeeds or everything fails.
            setVrequest.onfailure  = function(e) {     ......      };    
            setVrequest.onsuccess = function(e) {     
               ......    // we are good to setup database.  
             };
      }
   ..... // do as needed.
};


 Creating Object Stores and Indexes:

setVrequest.onsuccess = function(e) {     
   // Object Store creation is atomic and can only take place inside version 
   // changing transaction
   var store = db.createObjectStore(
         "name":"mysamplestore", // The store's name
         "key":"id",             // The property used as key.
           "autoIncrement":true  // yes it should be auto incrementing 
       );
       store.createIndex(
            "sampleIndex", //  name of the index
            "id",          //  the property to be indexed.
             true          // its unique constraint
       );
};


Write operation is asynchronous:
             
exampledb.indexedDB.writeToDB = function(dataToWrite){
   var db = exampledb.indexedDB.db;
   // create a transaction
   var writeTrans = db.transaction(
        ["mysamplestore"],         // Object Store to lock
        IDBTransaction.READ_WRITE  // Lock type   
   );
   //open the  store for writing
   var store = writeTrans.objectStore("mysamplestore");
   var writeRequest = store.put({
        "name": "binnash", // can be object 
        "url": "http://www.binnash.blogspot.com" // can be object too                         
   });
   writeRequest.onerror = function(e){
        writeTrans.abort(); // undo and roll back
   };
   writeRequest.onsuccess = function(e){ console.log(e);  };        
};   

          
Reading data is also asynchronous:
            
exampledb.indexedDB.readRecord =  function (){
   var db = exampledb.indexedDB.db;
    // create a transaction
    var readTrans = db.transaction(
          ["mysamplestore"],       // Object Store to lock
         IDBTransaction.READ_only  // Lock type   
    );
     //open the  store for writing
     var store = readTrans.objectStore("mysamplestore");
     var readCursor = store.openCursor();
     readCursor.onerror = function(e){
            // 
     };
     readCursor.onsuccess = function(e){ 
         if(e.result){
               console.log(e.target.result.value.url);
               e.target.result.continue();
         }else{
              // you've reached the end of the cursor's list.
          }
      };                           
}


Querying in the Object Store:

as usual Querying is also asynchronous.

exampledb.indexedDB.queryStore =  function (){
    var db = exampledb.indexedDB.db;
    // create a transaction
    var readTrans = db.transaction(
          ["mysamplestore"],       // Object Store to lock
         IDBTransaction.READ_only  // Lock type   
    );
    //open the  store for writing
    var store = readTrans.objectStore("mysamplestore");
    var bounds =new IDBKeyRange.bound(
           "a",            // Lower Bound
           "z",            // Upper Bound
            true,          // include lower bound?
            true           // include upper bound?
    ); 
    var readCursor = store.openCursor(bounds);
    readCursor.onerror = function(e){
          // 
    };
    readCursor.onsuccess = function(e){ 
         if(e.result){
             console.log(e.target.result.value.url);
             e.target.result.continue();
         }else{
             // you've reached the end of the cursor's list.
         }
    };
};


Deleting record:
 
exampledb.indexedDB.deleteItem =  function (id){
   var db = exampledb.indexedDB.db;
   // create a transaction
   var readTrans = db.transaction(
      ["mysamplestore"],           // Object Store to lock
      IDBTransaction.READ_WRITE  // Lock type   
   );
   //open the  store for writing
   var store = readTrans.objectStore("mysamplestore");
   var request = store.delete(id);
   readCursor.onerror = function(e){
      console.log(e);
   };
   readCursor.onsuccess = function(e){ 
     // update screen.
   };                           
};   


Wednesday, January 18, 2012

HTML5 series part 1: localStorage

HTML5 introduces client-side storage API which aims to cover the limitations of cookie and provide  much more.  in this article, i am going to explore about browser cookies, their limitations and how HTML5 overcomes these with client-side storage.

Legacy of HTTP cookie:
An HTTP cookie is a set of key/value pairs that an web server requests web browsers to store on local disk. when browser makes further requests to the server, it wraps all the cookie information in HTTP request header as long as the following conditions are met: ( ref: rfc2109)
1.The cookie is not expired.
2. The requested domain is same or subdomain of cookie storing domain .
3. The requested path is same of subpath of cookie storing domain.

browser  deletes cookie data when cookie expires.

Limitations of cookie:
 1. most current browsers limit cookie size to 4KB.
 2. Number of cookies in a domain is limited to 300
 3. when a site uses cookie, then every request must include all cookie data in HTTP header which is a performance issue.
4. cookie data is stored as plain text in client disk which can cause cookie/session hijacking.
5. cookie cannot differentiate between two different instances of same web application running in two different tabs or windows.

Age of client-side storage:
According to the web storage specification, web storage is intended to solve two cases that are not handled well by cookies:
1. The first is designed for scenarios where the user is carrying out a single transaction, but could be carrying out multiple transactions in different windows at the same time.
2. The second storage mechanism is designed for storage that spans multiple windows, and lasts beyond the current session. In particular, web applications may wish to store megabytes of user data, such as entire user-authered documents or a user's mailbox, on the client side for performance reasons.

Unlike cookie, web storage data is stored in the client by the browsers based on retention policies. Benefits are obvious:
1. data doesn't pass through HTTP request/response. bandwidth is saved.
2. as data isn't passed through network, this is relatively secure.this notion of security has some other advantages. This means that due to the inherent security feature, HTTPs connection can use plain HTTP. Because it wont need  to encrypt data since data is stored in client-side. Since HTTPs has only 10% of performance comparing with HTTP.
3. no download time means better user experience
4. with the help of web storage, surfing same web sites using more than one account simultaneously wont be a tough task.  You can experience this right now on google sites.
5. There is no 4KB limitation, web site will enjoy much more flexibility in storing large data in client.

localStorage API:
localStorage is a handy API included in HTML5 spec that gives web developers any easy to use 5MB store on the client's local machine. It's a simply key/value dictionary that allows developers to store primitive data types like integer, string etc. storing objects requires serialization into json format. localStorage doesn't provide transaction facilities. So wise usage can save you from race conditions.
data storing and retrieval is simple:

//save a value to localStorage
localStorage.setItem('key', 'value');
localStorage.key = value;
myObject = {a:1, b:2, c:3};
localStorage.setItem('key', JSON.stringfy(myObject));

//retrieve a value 
var value = localStorage.key;
var value = locaStorage.getItem('key');
var myStorageObject = JSON.parse(localStorage.getItem("key"));
//reset storage
localStorage.clear();

//to remove an item
localStorage.removeItem('key');

Important features of localStorage:
1. localStorage values on Secure (SSL) pages are isolated:
browsers isolates localStorage values based on HTML5 origin (scheme +hostname+unique port). so http://xyz.com is separated from https://xyz.com. firefox provides  globalStorage doesn't follow this distinction. 
2. sessionStorage values can survive browser restarts if browser impements session restore feature.
3. localStorage values created in "incognito" or private browsing mode are isolated. they will be gone as soon as the session ends.
4. localStorage quota for a site is 5 MB. it cannot be expanded. alternative means are available in the form of indexeddb and web SQL database.
//check if quota limited exceeded.
try{
     localStorage.setItem('key', value);
}catch(e){
      if(e== QUOTA_EXCEEDED_ERR) alert(file is too large);
}
5. for older IE browsers, localStorage feature can be implemented using IE-only feature userData.
//checking if localStorage support is available.
var supported = false;
 try{
    if(window['localStorage']!=null) supported = true;
}catch (e){
     supported = false;
}

for browser support issue, visit http://www.quirksmode.org/dom/html5.html

Monday, January 16, 2012

Facebook PHP SDK: Acquiring anytime access permission for your application

Facebook has exposed a lot of its core functionality through Graph API.  Third party application developers now can quite easily develop application that live on Facebook's gigantic database of user profile information.But except for the public information , applications are required to authenticate by the user to get access. facebook uses OAuth 2.0 protocol for authentication and authorization and supports a number of different OAuth flows that can be used to authorize and authenticate third party mobile/desktop applications and websites. but regardless of type of the flows, Facebook's OAuth implementation involves 3 steps: user authenticationapp authorization and app authentication (more about this can be found in facebook developer site). once these steps are complete, third party application is issued an "user access token" which enables the application to gain access to user infobase on users' behalf. By default,  user access token expires after 2 hours which is not good for site owners who want to show their facebook albums etc. on their sites. in that case, site owner has to be careful enough to authenticate once after every 2 hours which is annoying.  Guys at Facebook solved this  in a way they call "offline_access" permission. user access token with offline access permission doesn't expire. lets take a look at how offline access can be obtained and utilized in your application.

the easiest way to play around with Facebook Graph API is to use SDK. I'll use PHP SDK. First grab the SDK and include into your php file and instantiate SDK's Facebook class.

            require_once("facebook.php");
            $config = array();
            $config[‘appId’] = 'YOUR_APP_ID';
            $config[‘secret’] = 'YOUR_APP_SECRET';            
            $config['fileUpload'] = false;
            $config['cookie'] = true; // don't forget to enable cookie.
            $facebook = new Facebook($config);        
             
Once you have Facebook object, you can begin authentication process. Luckily SDK handles all the 3 steps of authentication on your behalf. all you need to do is to initiate the process and SDK will do the rest. As starter, we check if anyone is already logged in or not.
          $userId = $facebook->getUser();
if no one is logged in then above statement will return 0 otherwise it will return current user's  id.
          if($userId) {
              try{
                     // if user is logged in, we try to get his/her profile information
                     $user = $this->facebook->api('/me', 'GET');
                     // url you want facebook to redirect after logout
                     $logouturl = 'YOUR_SITE_URL';                
                     $logoutUrl = $this->facebook->getLogoutUrl(array('next'=>$logouturl));
                }
                catch(FacebookApiException $e){
                     //url you want facebook to redirect after login.
                     // a note of coution though, for security reason you need to inform facebook about this
                     // URL in your developer profile page.
                     $loginurl = 'YOUR_SITE_URL';

                     $params = array(
                              //This is where you request offline access token
                              scope => 'user_photos, friends_photos,offline_access',
                             redirect_uri => $loginurl
                    );          

                    $loginUrl = $this->facebook->getLoginUrl($params);
                }
         }      
once the authentication process is complete, you can get the access token in the following way:
                    $accessToken = $facebook->getAccessToken();
You should store the token for use across sessions. You can do the subsequent API calls as :
                    $facebook->setAccessToken($accessToken);
                    $facebook->api(/*polymorphic*/);






Saturday, January 14, 2012

End User License


End User License Agreement
Copyright, binnash
All rights reserved.

By using the software, you agree to be bound by the terms of this license. If you have any questions
about the terms below, please contact n.uddin.w@gmail.com for clarification.


1.) You must have paid the developer to use the software.

2.) The copyright holder retains all intellectual property rights to the software.

3.) You are granted the right to install the software on as many websites as you want, limited only to websites you own.

4.) You are granted the right to freely modify the software for your own personal use.

5.) You may not use code snippets from the software elsewhere.

6.) You may not re-distribute (either freely, or for any kind of compensation) the software, in whole or in part, to any 3rd party.

7.) You expressly acknowledge and agree that use of the software is at your sole risk. No warrantly is provided, either express or implied.