$value) { $value['file_updated'] = _minify_is_file_updated($value); $options[$key] = array( 'file_name' => _minify_file_name($value), 'version' => ($value['version']) ? $value['version'] : 'N/A', 'file_path' => _minify_file_path_links($value), 'status' => _minify_file_status($value), 'last_minify_at' => (0 != $value['last_minify_at']) ? format_date($value['last_minify_at'], 'medium') : 'N/A', 'original_size' => _minify_original_file_size($value), 'minified_size' => _minify_format_file_size($value['minified_size']), 'operations' => _minify_operation_links($value), ); } } $header = array( 'file_name' => t('File name'), 'version' => t('Version'), 'file_path' => t('File path'), 'status' => t('Status'), 'last_minify_at' => t('Last minified/refresh'), 'original_size' => t('Original size'), 'minified_size' => t('Minified size'), 'operations' => t('Operations'), ); $form['js'] = array( '#type' => 'tableselect', '#header' => $header, '#options' => $options, '#empty' => '' . t('JavaScript files not found, please visit some random pages at front end to capture JavaScript files.') . '', ); $form['minify'] = array( '#type' => 'submit', '#value' => t('Minify'), '#submit' => array('minify_js_submit'), ); $form['clear_minify_cache'] = array( '#type' => 'submit', '#value' => t('Clear minify cache'), '#submit' => array('minify_clear_js_cache'), ); return $form; } /** * Helper function to check file is updated or not, using file content MD5 */ function _minify_is_file_updated($details) { $md5 = md5_file(drupal_realpath($details['file_path'])); if ($details['md5'] != $md5 && $details['status']) { return true; } else { return false; } } /** * Helper function to construct file name also include file version if avaliable */ function _minify_file_name($details) { if ($details['file_updated']) { return '' . $details['file_name'] . ' '; } else { return $details['file_name']; } } function _minify_file_path_links($details) { return l('Original', $details['file_path'], array('attributes' => array('target' => '_blank', 'title' => $details['file_path']))) . (($details['status']) ? (' | ' . l('Minified', $details['minified_file_path'], array('attributes' => array('target' => '_blank', 'title' => $details['minified_file_path'])))) : '' ); } /** * Helper function to construct operation links */ function _minify_operation_links($details) { $refresh_link = l('Refresh', 'admin/config/development/performance/minifyjs/refresh', array('query' => array('file' => $details['file_path']), 'attributes' => array('title' => 'Refresh/regenerate the minified JS file.')) ); $revert_link = l('Revert', 'admin/config/development/performance/minifyjs/revert', array('query' => array('file' => $details['file_path']), 'attributes' => array('title' => 'Delete the minified file and use original file.')) ); $minify = l('Minify', 'admin/config/development/performance/minifyjs/refresh', array('query' => array('file' => $details['file_path']), 'attributes' => array('title' => 'Minify it.'))); return ($details['status']) ? ($refresh_link . ' | ' . $revert_link) : $minify; } /** * Helper function to get original file size */ function _minify_original_file_size($details) { $file_size = filesize(drupal_realpath($details['file_path'])); if ($details['file_updated']) { return '' . _minify_format_file_size($file_size) . ''; } else { return _minify_format_file_size($file_size); } } /** * Function to sort multidimensional array by column */ function _minify_sort_array_by_column(&$arr, $col, $dir = SORT_ASC) { $sort_col = array(); foreach ($arr as $key=> $row) { $sort_col[$key] = $row[$col]; } array_multisort($sort_col, $dir, $arr); } /** * Function to convert file size in human readable form */ function _minify_format_file_size($f_size) { if(0 == $f_size) { $f_size = 'N/A'; } elseif ($f_size >= 1048576) { $f_size = number_format($f_size / 1048576, 2) . ' MB'; } elseif ($f_size >= 1024) { $f_size = number_format($f_size / 1024, 2) . ' KB'; } elseif ($f_size > 1) { $f_size = $f_size . ' bytes'; } return $f_size; } /** * Function to return file status */ function _minify_file_status($details) { if ($details['file_updated'] && $details['status']) { $status = ' Need to refresh'; } else if ($details['status']) { $status = 'Minified'; } else { $status = 'Non-minified'; } return $status; } /** * Submit function to handle overview for submission */ function minify_js_submit($form, &$form_state) { /* Filter out non-selected values */ $selected_scripts = array_filter($form_state['values']['js']); $operations = array(); foreach ($selected_scripts as $script) { $operations[] = array('minify_batch_process', array($script)); } $batch = array( 'title' => t('Minify'), 'init_message' => t('Minify starting.'), 'operations' => $operations, 'file' => drupal_get_path('module', 'minify') . '/' . 'minify.admin.inc', ); batch_set($batch); /* Setting redirect in batch_process */ batch_process('admin/config/development/performance/minifyjs'); } /** * Function to execute minify batch process */ function minify_batch_process($script, &$context) { $cache_data = variable_get('minify_captured_js', array()); $info = pathinfo($script); $context['message'] = t('Now processing @file_name', array('@file_name' => $info['basename'])); _minify_process_minify($script, $cache_data); } /** * Submit callback to clear captured data */ function minify_clear_js_cache($form, &$form_state) { $minify_dir = variable_get('file_public_path', conf_path() . '/files') . '/minify'; $files = file_scan_directory($minify_dir, '/.*\.*$/'); foreach ($files as $key => $value) { drupal_unlink($key); } variable_del('minify_captured_js'); watchdog('minify', 'Minify cache cleared.', array(), WATCHDOG_NOTICE); drupal_set_message(t('Minify cache cleared.')); drupal_goto('admin/config/development/performance/minifyjs'); } /** * Helper function to process minify call */ function _minify_process_minify($script, &$cache_data) { $js_code = urlencode(trim(file_get_contents(drupal_realpath($script)))); $post_data = _minify_get_post_fields($js_code); $response = _minify_send_request($post_data); if (isset($response['response'])) { $response_obj = $response['response']; if (!isset($response_obj->warnings) && !isset($response_obj->serverErrors)) { $min_js_path = _minify_construct_min_js_path($script, $cache_data); if (file_put_contents($min_js_path, $response_obj->compiledCode)) { watchdog('minify', '%old_path minified successfully as %new_path.', array('%old_path' => $script, '%new_path' => $min_js_path), WATCHDOG_NOTICE); drupal_set_message(t('%file_name minified successfully.', array('%file_name' => $cache_data[$script]['file_name']))); $cache_data[$script]['minified_file_path'] = $min_js_path; $cache_data[$script]['minified_size'] = $response_obj->statistics->compressedSize; $cache_data[$script]['status'] = true; $cache_data[$script]['last_minify_at'] = time(); $cache_data[$script]['error'] = false; $cache_data[$script]['error_msg'] = null; $cache_data[$script]['md5'] = md5_file(drupal_realpath($script)); } //File save if end } else if (isset($response_obj->warnings)) { $warning = $response_obj->warnings[0]->warning; $cache_data[$script]['error'] = true; $cache_data[$script]['error_msg'] = $warning; watchdog('minify', 'Failed to generate minified JS. Error: %warning', array('%warning' => $warning), WATCHDOG_ERROR); form_set_error('null', t('Failed to generate minified JS. Error: %warning', array('%warning' => $warning))); } else if (isset($response_obj->serverErrors)) { watchdog('minify', 'Server error, Too many compiles performed recently. Try again later.', array(), WATCHDOG_ERROR); form_set_error('null', t('Server error, Too many compiles performed recently. Try again later.')); } /* Update the cache */ variable_set('minify_captured_js', $cache_data); } // Response isset if end } /** * Helper function to construct post request data */ function _minify_get_post_fields($js_code) { $post_data_array = array(); $post_data_array[] = 'js_code=' . $js_code; $post_data_array[] = 'compilation_level=WHITESPACE_ONLY'; $post_data_array[] = 'output_format=json'; $post_data_array[] = 'warning_level=QUIET'; $post_data_array[] = 'use_closure_library=' . true; $post_data_array[] = 'output_info=warnings'; $post_data_array[] = 'output_info=errors'; $post_data_array[] = 'output_info=compiled_code'; $post_data_array[] = 'output_info=statistics'; /* Prepare POST request query string */ return implode('&', $post_data_array); } /** * Helper function to send CURL request */ function _minify_send_request($post_data) { if (function_exists('curl_init')) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, "https://closure-compiler.appspot.com/compile"); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data); curl_setopt($curl, CURLOPT_POST, true); $response = json_decode(curl_exec($curl)); $httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); return array('response' => $response, 'http_code' => $httpcode); } } /** * Helper function to construct minified js path */ function _minify_construct_min_js_path($script, $cache_data) { if ($cache_data[$script]['status']) { /* Already minified i.e. update case return existing path */ return $cache_data[$script]['minified_file_path']; } else { /* Not minified file */ $minify_js_dir = variable_get('file_public_path', conf_path() . '/files') . '/minify/'; if (!is_dir($minify_js_dir)) { drupal_mkdir($minify_js_dir); } $version = $cache_data[$script]['version']; $path_parts = pathinfo($script); $file_name = $path_parts['filename']; $file_ext = $path_parts['extension']; $min_file_name = implode('.', array_filter(array($file_name, trim($version), 'min', $file_ext))); $min_file_path = $minify_js_dir . $min_file_name; $min_file_path = file_destination($min_file_path, FILE_EXISTS_RENAME); return $min_file_path; } } /** * Helper function to remove minified js from cache */ function _minify_js_revert_callback() { $cache_data = variable_get('minify_captured_js', array()); if (!empty($cache_data)) { $key = $_GET['file']; if (isset($cache_data[$key])) { /* Reset cache data record to prevent use of minified js */ $minified_file_path = $cache_data[$key]['minified_file_path']; $cache_data[$key]['minified_file_path'] = null; $cache_data[$key]['minified_size'] = 0; $cache_data[$key]['status'] = false; $cache_data[$key]['last_minify_at'] = 0; $cache_data[$key]['error'] = false; $cache_data[$key]['error_msg'] = null; $cache_data[$key]['skip'] = false; $cache_data[$key]['md5'] = null; variable_set('minify_captured_js', $cache_data); /* delete the file */ drupal_unlink($minified_file_path); $file_name = $cache_data[$key]['file_name']; watchdog('minify', '%file_name reverted successfully.', array('%file_name' => $file_name), WATCHDOG_NOTICE); drupal_set_message(t('%file_name reverted successfully.', array('%file_name' => $file_name))); } } drupal_goto('admin/config/development/performance/minifyjs'); } /** * Helper function to regenerate minified js */ function _minify_js_refresh_callback() { $file = $_GET['file']; $cache_data = variable_get('minify_captured_js', array()); _minify_process_minify($file, $cache_data); drupal_goto('admin/config/development/performance/minifyjs'); } /** * Helper function to clear invalid cache * check original file is exist or not * if not, delete minified file and remove record from cache */ function _minify_clear_invalid_cache() { $cache = variable_get('minify_captured_js', array()); foreach ($cache as $key => $value) { if (!file_exists($key)) { if (file_exists($value['minified_file_path'])) { drupal_unlink($value['minified_file_path']); } unset($cache[$key]); } } variable_set('minify_captured_js', $cache); }