I have written the following script which simply:
- Loops through JavaScript files (either defined in a particular package, or separately with the libraries array)
- Reads the files into the script and combines them into one string
- Minifies the string and saves the contents to a cached file on the server and returns the contents.
Some key features:
- The cached file is only updated when the script detects that one of the loaded JavaScript libraries has been modified
- The script only gathers the files if a cached version does not exist
I am sure most of us programmers will notice that the array of libraries could very easily be built dynamically by scanning the _js/_source/
directory and therefore I would not have to add each library to the $js_libraries
array individually. The reason I have not done this is simple, it is much slower when there are a lot of files and the absolute key of this script is speed!
I simply want to know whether this could be written better and whether it has any areas I could improve on.
<?php /** * Sine Macula Package API * The Sine Macula Package API loads and packs documents ready to * be returned to the browser * @name jsapi.php * @author Ben Carey * @version 1.0 * @date 24/10/2012 * @copyright (c) 2012 Sine Macula Limited (sinemaculammviii.com) */ // Retrieve the supplied variables $package = $_REQUEST['package'] ? strtolower($_REQUEST['package']) : 'all'; $packageURL = $_REQUEST['packageURL']; $libraries = strtolower($_REQUEST['libraries']); // Define all the javascript libraries $js_libraries = array( 'md5' => '/_js/_source/_md5/sinemacula.md5.js', 'cookies' => '/_js/_source/_cookies/sinemacula.cookies.js', 'preloading' => '/_js/_source/_preloading/sinemacula.preloading.js', 'browsers' => '/_js/_source/_browsers/sinemacula.browsers.js', 'overlay' => '/_js/_source/_overlay/sinemacula.overlay.js', 'forms' => '/_js/_source/_forms/sinemacula.forms.js', 'fancybox' => '/_js/_source/_fancybox/jQuery.lightbox-0.5.js', 'indexof' => '/_js/_source/_indexOf/init.indexOf.js' // This array will be much larger ); // Only define the javascript packages if the // package is not coming from an external source if($package){ // Define all the javascript packages $js_packages = array( 'all' => array_keys($js_libraries) // This array will be much larger ); // Make sure the supplied package exists if(array_key_exists($package,$js_packages)){ // Gather all the libraries for the particular package $package = array_intersect_key($js_libraries,array_flip($js_packages[$package])); }else{ $errors[] = 'The supplied package does not exist'; } }elseif($packageURL){ // Attempt to retrieve the contents of the external package $package = @file_get_contents($packageURL); if($package){ // Decode the JSON object into an array $package = json_decode($package,true); }else{ $errors[] = 'Error retrieving package from remote source'; } } // Add the libraries to the package array // if they have been supplied if($libraries){ // Explode the libraries string into an array $libraries = explode(',',$libraries); // Gather the unrecognised libraries $unrecognised_libraries = array_diff($libraries,array_keys($js_libraries)); // If there are unrecognised libraries then // return relevant errors if($unrecognised_libraries){ foreach($unrecognised_libraries as $value){ $errors[] = '\''.$value.'\' library does not exist'; } } // Insert all the sources for the library keys $libraries = array_intersect_key($js_libraries,array_flip($libraries)); // Make sure package is an array $package = is_array($package) ? $package : array(); // Merge the libraries with the package array $package = array_merge($package,$libraries); } // Create a hash of the package $package_hash = md5(implode('',array_keys($package))); // Loop through the package and check their modified dates $modified_timestamps = array_map(function($a){ // Get the modified time of each individual library return filemtime(dirname(__FILE__).$a); },$package); // Hash the modified time, this will determine whether the, // library has been updated $modified_hash = md5(implode('',$modified_timestamps)); // Check to see if the package directory exists in the cache if(@is_dir(dirname(__FILE__).'/_js/_cache/_' . $package_hash )){ // If the modified hash matches a file in the folder then it // does not need updating if(file_exists(dirname(__FILE__).'/_js/_cache/_'.$package_hash.'/'.$modified_hash.'.js')){ // Get the contents of the file $packed_script = file_get_contents(dirname(__FILE__).'/_js/_cache/_'.$package_hash.'/'.$modified_hash.'.js'); }else{ // Set pack to true to ensure that the script // is created $pack = true; } }else{ // Create the directory for the package @mkdir(dirname(__FILE__).'/_js/_cache/_'.$package_hash); // Set pack to true to ensure that the script // is created $pack = true; } // If pack is set then gather all the files, combine // into one and pack. This will create the file as // well, and store it in the folder '_cache' if($pack){ // Loop through the package and load all of the libraries // into the script ready to be packed foreach($package as $key => $value){ // Get the script $current_script = @file_get_contents(dirname(__FILE__).$value); // Return an error on fail to load if($current_script){ $combined_script .= $current_script.";\n"; }else{ $errors[] = 'Failed to load \''.$key.'\' library'; } } // Include the javascript packer require_once(dirname(__FILE__).'/_php/_classes/class.packer.php'); // Initiate the packer and pack the javascript $js_packer = new JavaScriptPacker($combined_script); $packed_script = $js_packer->pack(); // Retrieve the cached scripts (should only be one) $cached_scripts = @glob(dirname(__FILE__).'/_js/_cache/_'.$package_hash.'/*.js'); // Delete all the files in the package directory if(is_array($cached_scripts)){ array_map('unlink',$cached_scripts); } // Create the new javascript package file if there // have been no errors if(empty($errors)){ if(!@file_put_contents(dirname(__FILE__).'/_js/_cache/_'.$package_hash.'/'.$modified_hash.'.js',$packed_script)){ $errors[] = 'There was an error loading the javascript libraries'; } } } // Set the content header to javascript // and write the packed script or errors header("Content-Type: text/javascript"); if(empty($errors)){ echo $packed_script; }else{ // Loop through the errors and write them to the // javascript console foreach($errors as $value){ echo 'console.log("'.$value.'");'; } } ?>