js_root = $config['js_root']; $this->js_group = $groups[$group]; $this->js_groups_file = $config['js_groups_file']; $this->cache_file = "{$this->js_root}cache/{$group}"; $this->last_modified = $this->get_last_modified(); $this->cache_modified = (is_file($this->cache_file)) ? filemtime($this->cache_file) : 0; // Output some JS! $this->send(); } protected function send() { // Override caching if debug key is set if($this->is_debug_call()) { return $this->output($this->get_files()); } // If the browser's cached version is up to date, // don't resend the file if($this->last_modified == $this->get_if_modified() && $this->is_not_debug()) { throw new FileNotChangedException(); } if($this->cache_modified < $this->last_modified) { $js = $this->minify($this->get_files()); //Make sure cache file gets created/updated if (file_put_contents($this->cache_file, $js) === FALSE) { echo 'Cache file was not created. Make sure you have the correct folder permissions.'; return; } return $this->output($js); } else { return $this->output(file_get_contents($this->cache_file)); } } /** * Makes a call to google closure compiler service * * @param array $options - Form parameters * @return object */ protected function closure_call(array $options) { $client = new Client(); $response = $client->post('http://closure-compiler.appspot.com/compile', [ 'headers' => [ 'Accept-Encoding' => 'gzip', 'Content-type' => 'application/x-www-form-urlencoded' ], 'form_params' => $options ]); return $response; } /** * Do a call to the closure compiler to check for compilation errors * * @param array $options * @return void */ protected function check_minify_errors($options) { $error_res = $this->closure_call($options); $error_json = $error_res->getBody(); $error_obj = json_decode($error_json) ?: (object)[]; // Show error if exists if ( ! empty($error_obj->errors) || ! empty($error_obj->serverErrors)) { $error_json = json_encode($error_obj, JSON_PRETTY_PRINT); header('Content-type: application/javascript'); echo "console.error(${error_json});"; die(); } } /** * Get Files * * Concatenates the javascript files for the current * group as a string * * @return string */ protected function get_files() { $js = ''; foreach($this->js_group as $file) { $new_file = realpath("{$this->js_root}{$file}"); $js .= file_get_contents($new_file) . "\n\n"; } return $js; } /** * Get the most recent modified date * * @return int */ protected function get_last_modified() { $modified = array(); foreach($this->js_group as $file) { $new_file = realpath("{$this->js_root}{$file}"); $modified[] = filemtime($new_file); } //Add this page too, as well as the groups file $modified[] = filemtime(__FILE__); $modified[] = filemtime($this->js_groups_file); rsort($modified); $last_modified = $modified[0]; return $last_modified; } /** * Minifies javascript using google's closure compiler * * @param string $js * @return string */ protected function minify($js) { $options = [ 'output_info' => 'errors', 'output_format' => 'json', 'compilation_level' => 'SIMPLE_OPTIMIZATIONS', //'compilation_level' => 'ADVANCED_OPTIMIZATIONS', 'js_code' => $js, 'language' => 'ECMASCRIPT6_STRICT', 'language_out' => 'ECMASCRIPT5_STRICT' ]; // Check for errors $this->check_minify_errors($options); // Now actually retrieve the compiled code $options['output_info'] = 'compiled_code'; $res = $this->closure_call($options); $json = $res->getBody(); $obj = json_decode($json); return $obj->compiledCode; } /** * Output the minified javascript * * @param string $js * @return void */ protected function output($js) { $this->send_final_output($js, 'application/javascript', $this->last_modified); } } // -------------------------------------------------------------------------- // ! Start Minifying // -------------------------------------------------------------------------- $config = require_once('config/config.php'); $groups = require_once($config['js_groups_file']); $cache_dir = "{$config['js_root']}cache"; if ( ! is_dir($cache_dir)) { mkdir($cache_dir); } if ( ! array_key_exists($_GET['g'], $groups)) { throw new InvalidArgumentException('You must specify a js group that exists'); } try { new JSMin($config, $groups); } catch (FileNotChangedException $e) { BaseMin::send304(); } //end of js.php