Support This Project <?php

/* DojoCompiler v1.0.03
*
* Written by John Beaven, November 06; Released under the LGPL.
*
* DojoCompiler is currently in use in a production environment! Check out:
*
*         http://www.diginote.info (see example, tab on top right)
*
* DojoCompiler is used to reduce bandwidth usage and improve efficiency on the diginote
* website!
*
*
* DojoCompiler is a server side linker and compiler (written in PHP and
* javascript) that removes the dependencies dojo.js (the javascript toolkit)
* has on other files within the Dojo package - it compiles all the files
* required  by your site into one script on the fly. The server is developed
* in a way that ensures the visitors browser only re-downloads the compiled
* script when changes have been made to your web site pages (ie, when there
* are new dependencies on Dojo.) The system saves bandwidth, and significantly
* reduces the overhead required by Dojo when downloading required files. The
* compiler also compresses the existing Dojo package files to some extent.
*
* Usage - simply drop into the same directory as dojo.js (on a php enabled
* server) and change references within your pages from dojo.js to
* dojocompiler.php
*
* NOTE: The script will fail to work correctly if the ./cache/ directory is
* not included in the same folder and made writable.
*
* How it all works:
*
*  The system is quite simple. DojoCompiler outputs the contents of dojo.js, plus
*  some extra functions. The getText function in the dojo toolkit is used by dojo
*  to fetch data from a specific uri. DojoCompiler overrides getText and forces
*  dojo to check for a cached version of the data. If DojoCompiler finds a cached version, it
*  emulates the original behaviour of getText using the cached data. If DojoCompiler
*  fails to find a cached version, it notifies the server of the missing
*  dependency and the dependency is compiled into the cache for future inclusion.
*  Dojo then carries on as it would normally.
*
*  Cached data is stored in "packages". You can opt to create a package for every page
*  on your site (which load quickly, but need to reload on each page the visitor
*  goes to) or a single package for the entire site (which is slow to
*  load, but once loaded is used on every page of your site and so is only downloaded
*  once by the visitor and subsequent pages load faster)
*
*  As dojo dependencies (javascript, html and css files) are compiled into the
*  cache they are optimized for size to reduce bandwidth consumption (currently
*  only minimal optimization is performed, but hopefully this will improve in the
*  future..)
*/

//you have the option of compiling one package that will be shared between all
//pages on your site (false) or compiling a package for each page on your site (true).
//If you choose the former, a visitor will have to download one big file once that will
//be used on every page. With the latter, a little file is downloaded each time the
//visitor goes to a page on your site that contains dojo code.
$package_per_page = false ;

//the name of this file! Only change if you rename this file..
$script_name = 'dojocompiler.php' ;

//***The following three variables may need to be overridden to work on your server:

//$base_path: this value is passed to dojo, and is the folder relative to server root
//eg, for http://www.domain.com/dojo/dojo.js, $base_path would be '/dojo/'
$base_path = str_replace ( $script_name , '' , $_SERVER [ 'REDIRECT_URL' ]? $_SERVER [ 'REDIRECT_URL' ]: $_SERVER [ 'PHP_SELF' ]);

//$abs_path: path of dojo.js relative to home..
$abs_path = str_replace ( $script_name , '' , $_SERVER [ 'SCRIPT_FILENAME' ]);

//$full_uri: full URI to dojo.js path, eg http://www.domain.com/dojo/
$full_uri = 'http://' . $_SERVER [ 'HTTP_HOST' ]. $base_path ;



//this section is called when Dojo is telling us there's more bits and pieces
//it needs compiling into the package. Each time a dependency is first detected,
//this section is called to incorporate the dependency..
if( $_GET [ 'action' ] == 'add' ) {
    
    
//just output plain text - only visible when debugging..
    
header ( 'Content-type: text/plain' );
    
    if(
$package_per_page ) {
        
        
$package_id = $_GET [ 'cid' ];
        
        
//sanitize..
        
$package_id = preg_replace ( '/[^a-zA-Z0-9]/' , '' , $package_id );
        
        
$cache_file_path = 'cache/' . $package_id ;
        
        } else {
        
        
$cache_file_path = 'cache/all' ;
    }
    
    
//the uri points to the dependency required by Dojo that is not already linked..
    
$uri = $_GET [ 'uri' ];
    
    
//calculate the absolute path and url to the file using the relative uri..
    
$uri_rel_top = substr_replace ( $uri , '' , 0 , strlen ( $base_path ));
    
$uri_url = $full_uri . $uri_rel_top ;
    
$uri_path = $abs_path . $uri_rel_top ;
    
    
//make sure the file exists on our server - major security risk otherwise!
    
if( file_exists ( $uri_path )) {
        
        
//load up the cache file data..
        
$cache_data = file_get_contents ( $cache_file_path );
        
        
//make sure the uri isn't already listed - dont want dupes..
        
if( strpos ( $cache_data , "/*djc*/ case '$uri'" ) === false ) {
            
            
//it's not, so process the data..
            //load the data using the URL to the file - we want the internets' view of
            //the file not the server side view - otherwise the utility could be used
            //to expose the contents of any file on our server.. nicht gut!
            
$data = file_get_contents ( $uri_url );
            
            
//if it's a js then we can optimise the code..
            
if( strpos ( $uri , '.js' ) !== false ) {
                
                
//assume js files start with a /**/ comment (all dojo files do..)
                //this can be safely removed to save a little bandwidth..
                
$data = preg_replace ( '{\/\*.*\*\/}sU' , '' , $data , 1 );
                
                
/* It would be useful to process the javascript file data before storing -
                * maybe stripping all comments and debug info from the files once loaded.
                *
                * This would save huge amounts of bandwidth and disk space - if anyone has
                * any reg-exs for such a purpose then please send me a copy ;) the problem
                * is determining what's a javascript comment and whats a sequence within a
                * string that happens to look like a comment..
                */
                
            
}
            
            
//escape newlines and quotes so that the data can be incorporated into a javascript string..
            
$data = str_replace (array( "\\" , "\r\n" , "\n" , "'" ), array( "\\\\" , "\\r\\n" , "\\n" , "\\'" ), $data );
            
            
//the data will be incorporated into a try-catch:
            
$data = "/*djc*/ case '$uri' : return '$data'; \n " ;
            
            
//store data in the cache so that it can be included with the next call..
            
$f = fopen ( $cache_file_path , "a" );
            
            if(
$f ) {
                
                
fwrite ( $f , $data );
                
fclose ( $f );
            }
            
            
//report success in case we're in debug mode..
            
print 'OK' ;
            
            } else {
            
            
//report problem in case we're in debug mode..
            
print 'FAILED: duplicate entry: ' . $uri_url . '; ' . $_SERVER [ 'QUERY_STRING' ];
        }
        
        } else {
        
        
//report problem in case we're in debug mode..
        
print 'FAILED: uri not found: ' . $uri_url . '; ' . $_SERVER [ 'QUERY_STRING' ];
    }
    
    exit;
}


//this section displays the compiled dojo.js
//obviously all output from this section is javascript..

if( $package_per_page ) {
    
    
$ref = md5 ( $_SERVER [ 'HTTP_REFERER' ]);
    
$cache_file_path = 'cache/' . $ref ;
    
    } else {
    
    
$ref = '' ;
    
$cache_file_path = 'cache/all' ;
}

//tell browser it's JS..
header ( 'Content-type: application/x-javascript' );

//warn you if cannot find dojo.js..
if(! file_exists ( 'dojo.js' )) {
    print
"alert('unable to find dojo.js!');" ;
    exit;
}

//check age of cache periodically - delete if created over X days ago..
if( false ) {
    
//the cache is stale, remove it..
    
    
unlink ( $cache_file_path );
}

//if a cache file exists and the client has a cached version, check to see if it needs updating..
if( file_exists ( $cache_file_path )) {
    
    
$headers = apache_request_headers ();
    
$last_mod_timestamp = filemtime ( $cache_file_path );
    
    if (isset(
$headers [ 'If-Modified-Since' ]) && ( strtotime ( $headers [ 'If-Modified-Since' ]) == $last_mod_timestamp )) {
        
// Client's cache is current, so we just respond '304 Not Modified'.
        
header ( 'Last-Modified: ' . gmdate ( 'D, d M Y H:i:s' , $last_mod_timestamp ). ' GMT' , true , 304 );
        exit;
        } else {
        
//not cached or cache outdated, we respond '200 OK' and output the data.
        
header ( 'Last-Modified: ' . gmdate ( 'D, d M Y H:i:s' , $last_mod_timestamp ). ' GMT' , true , 200 );
    }
}

//because we are using a php script, dojos automatic config fails to find the correct
//base path and uri - set it here so that dojo doesn't have to stress over it..
print 'if(djConfig){djConfig["baseRelativePath"]="' . $base_path . '";djConfig["baseScriptUri"]="' . $base_path . '";}else djConfig={baseScriptUri:"' . $base_path . '",baseRelativePath:"' . $base_path . '"};' . "\n" ;

//output dojo.js..
print file_get_contents ( 'dojo.js' );

/*
What the following javascript functions do:

dojo.hostenv.fetchFromCache(uri):

the dojo system passes in uris of files it requires, and this function returns
any cached data it contains. If the data for a uri is not found then "null" is
returned.

dojo.hostenv.addUriToCache(uri):

blindly calls this php script and adds a dependency that must be linked into
the current package.

dojo.hostenv.getText(uri, async_cb, fail_ok):

over-rides the existing dojo function of the same name and incorporates the
caching/linking/compiling functionality. If a cached version of the uri is
found then the the original behaviour of getText is emulated using the cached
data. If the data is not found then addUriToCache() is called and the uri is
added to the cache, then the script continues to load the data as though the
DojoCompiler was not present. The original getText can be accessed using
getText_Original().

uncomment the //if(console&&console.debug)console.debug(... lines to view extra
debug data within firebug..
*/
?>


dojo.hostenv.fetchFromCache = function(uri) {
    
    //sometimes a uri object is passed in, not a string - screws up the switch so extract string..
    if(uri&&uri.toString) uri = uri.toString();
    
    switch(uri) {
        
         <?php
        
        
if( file_exists ( $cache_file_path ))
        print
file_get_contents ( $cache_file_path );
        
        
?>
    }
    
    return null;
}


dojo.hostenv.addUriToCache = function(uri) {
    
    //if(console&&console.debug)console.debug('add to cache: "'+uri+'"');
    
    var http = this.getXmlhttpObject();
    http.open('GET', ' <?php print $full_uri . $script_name ?> ?action=add&cid= <?php print $ref ; ?> &uri='+escape(uri), true);
    try{
        http.send(null);
        //if(console&&console.debug)console.debug(http.responseText);
        }  catch(e) {
        
        alert(e);
    }
}

dojo.hostenv.getText_Original = dojo.hostenv.getText;

dojo.hostenv.getText = function(uri, async_cb, fail_ok){
    
    //if(uri.indexOf('__NO_CACHE__') == -1) {
        
        //check to see if we've already cached this url..
        var data = dojo.hostenv.fetchFromCache(uri);
        
        if(data != null) { //emulate a normal call using the cached data..
            
            //if(console&&console.debug)console.debug('found in cache: '+uri);
            
            if(async_cb)async_cb(data);
            return data;
        }
        
        //if not, tell the cache we want it next time..
        dojo.hostenv.addUriToCache(uri);
    //}
    
    //carry on as though we were never here...
    return dojo.hostenv.getText_Original(uri, async_cb, fail_ok);
}