array(), 'js' => array() ); var $asset_groups = array('css' => array(), 'js' => array()); var $enable_csstidy = FALSE; var $csstidy_loaded = FALSE; var $css; var $csstidy; var $csstidy_config = array(); var $csstidy_template = ''; var $enable_jsmin = FALSE; var $jsmin_loaded = FALSE; var $jsmin; var $js; var $default_group_css = ''; var $default_group_js = ''; var $renew_cache_css = array(); var $renew_cache_js = array(); var $cache_dir_css = '/'; var $cache_dir_js = '/'; var $cache_file_css = ''; var $cache_file_js = ''; var $gzip_compress_css = TRUE; var $gzip_compress_js = TRUE; var $force_cache_css = TRUE; var $force_cache_js = TRUE; function __construct() { $this->CI = get_instance(); log_message('debug', 'Assetlibpro library loaded'); $this->default_group_css = $this->CI->config->item('alp_default_group_css'); $this->default_group_js = $this->CI->config->item('alp_default_group_js'); $this->cache_dir_css = $this->CI->config->item('alp_cache_dir_css'); $this->cache_dir_js = $this->CI->config->item('alp_cache_dir_js'); // Changed because it was allways refreshing cache $this->cache_dir_css = realpath(trim($this->CI->config->item('alp_cache_dir_css'), "/")); $this->cache_dir_js = realpath(trim($this->CI->config->item('alp_cache_dir_js'), "/")); // $this->_load_css_config(); // $this->_load_js_config(); } /** * Add a CSS asset to the queue * @param Path to file (relative from CI's master index.php file) * @param Option for defining a media type for CSS files. **/ function add_css($file, $media = '') { if (empty($media)) $media = $this->default_group_css; if (!in_array($media, array('all', 'aural', 'braille', 'embossed', 'handheld', 'print', 'projection', 'screen', 'tty', 'tv'))) return FALSE; $this->_add($file, $media); } /** * Add a Javascript asset to the queue * @param Path to file (relative from CI's master index.php file) * @param Option for splitting up JS files. **/ function add_js($file, $group = '') { if (empty($group)) $group = $this->default_group_js; if (!is_string($group)) return FALSE; $this->_add($file, $group); } /** * Add an asset to the queue * @param Path to file (relative from CI's master index.php file) * @param Option for defining a media type for CSS files or just for splitting up JS files. **/ private function _add($file, $group = NULL) { $file_path = $file; if ($group === NULL) return FALSE; $file = realpath(trim($file, "/")); if (file_exists($file) && is_readable($file)) { $fileinfo = pathinfo($file); if ($fileinfo['extension'] === 'js' || $fileinfo['extension'] === 'css') { $this->_assets[$fileinfo['extension']][$group][$file_path] = ''; if (!in_array($group,$this->asset_groups[$fileinfo['extension']])) $this->asset_groups[$fileinfo['extension']][] = $group; } } } /** * Load the config values of the JS componente * @param All the stuff that needs to be done before actuallyly processing any files **/ private function _prepare_assets($type = 'all'){ if ($type == 'all') { $this->_prepare_assets('css'); $this->_prepare_assets('js'); } if ($type == 'css') { $has_assets = FALSE; foreach ($this->_assets['css'] as $array) { if (!empty($array)) $has_assets = TRUE; break; } if (!$has_assets) return FALSE; $this->cache_file_css = array($this->default_group_css => ''); $options = array( $this->gzip_compress_css, $this->force_cache_css, $this->enable_csstidy, $this->csstidy_template, $this->csstidy_config ); } else if ($type == 'js') { $has_assets = FALSE; foreach ($this->_assets['js'] as $array) { if (!empty($array)) { $has_assets = TRUE; break; } } if (!$has_assets) return FALSE; $this->cache_file_js = array($this->default_group_js => ''); $options = array( $this->gzip_compress_js, $this->force_cache_js, $this->enable_jsmin ); } foreach ($this->asset_groups[$type] as $group) { $assets = array_keys($this->_assets[$type][$group]); $mtimes = array(); foreach ($assets as $asset) { $mtimes[] = filemtime(dirname(FCPATH).'/'.trim($asset,'/')); } $assets_hash = md5(implode('',$assets)); $options_hash = md5(serialize($options)); $changes_hash = md5(serialize($mtimes)); $file_name = $type.'_'.$group.'_'.substr($assets_hash,0,8).'_'.substr($options_hash,0,8).'_'.substr($changes_hash,0,8).'.php'; if ($type == 'css') { $this->cache_file_css[$group] = $file_name; $this->renew_cache_css[$group] = (file_exists($this->cache_dir_css.'/'.$this->cache_file_css[$group])) ? FALSE : TRUE; if ($this->renew_cache_css[$group]) $this->_load_css_config(); } else if ($type == 'js') { $this->cache_file_js[$group] = $file_name; $this->renew_cache_js[$group] = (file_exists($this->cache_dir_js.'/'.$this->cache_file_js[$group])) ? FALSE : TRUE; if ($this->renew_cache_js[$group]) $this->_load_js_config(); } } } /** * Load the config values of the JS componente * @param Which's assets link to print (either 'css', 'js' or 'all') **/ function output($type = 'all'){ if ($type == 'all') { $css = $this->output('css'); $js = $this->output('js'); return "$css\n$js";//return string outputs of both functions. } $has_assets = FALSE; foreach ($this->_assets[$type] as $key => $array) { if (!empty($array)) { $has_assets = TRUE; break; } } if (!$has_assets) return FALSE; $this->_prepare_assets($type); if ($type == 'css') { foreach ($this->asset_groups[$type] as $group) { if ($this->renew_cache_css[$group] === TRUE) { $file_paths = array_keys($this->_assets[$type][$group]); foreach ($file_paths as $file_path) { $this->_assets[$type][$group][$file_path] = file_get_contents(realpath(trim($file_path, "/"))); } $this->_unlink_old_caches($this->cache_dir_css, $this->cache_file_css[$group]); $this->_fix_css_urls($group); if ($this->enable_csstidy === TRUE){ $this->csstidy->parse(implode(array_values($this->_assets[$type][$group]), "\n")); $this->css = $this->csstidy->print->plain(); } else { $this->css = implode(array_values($this->_assets[$type][$group]), "\n"); } $http_headers = ''; if ($this->gzip_compress_css === TRUE || $this->gzip_compress_css === TRUE) { $http_headers .= $this->_http_headers($type, $this->gzip_compress_css, $this->force_cache_css); } $this->css = $http_headers."\n".$this->css; echo $this->cache_dir_css.'/'.$this->cache_file_css[$group]; file_put_contents($this->cache_dir_css.'/'.$this->cache_file_css[$group], $this->css); } } } else if ($type == 'js') { foreach ($this->asset_groups[$type] as $group) { if ($this->renew_cache_js[$group] === TRUE) { $file_paths = array_keys($this->_assets[$type][$group]); foreach ($file_paths as $file_path) { $this->_assets[$type][$group][$file_path] = file_get_contents(realpath(trim($file_path, "/"))); } $this->_unlink_old_caches($this->cache_dir_js, $this->cache_file_js[$group]); if ($this->enable_jsmin === TRUE){ $js = implode(array_values($this->_assets[$type][$group])); $this->js = JSmin::minify($js); } else { $this->js = implode(array_values($this->_assets[$type][$group])); } $http_headers = ''; if ($this->gzip_compress_js === TRUE || $this->force_cache_js === TRUE) { $http_headers .= $this->_http_headers($type, $this->gzip_compress_js, $this->force_cache_js); } $this->js = $http_headers."\n".$this->js; file_put_contents($this->cache_dir_js.'/'.$this->cache_file_js[$group], $this->js); } } } $output = ''; if ($type == 'css') { foreach ($this->asset_groups[$type] as $group) { $output .= "CI->config->item('alp_cache_dir_css'), "/").$this->cache_file_css[$group]."\" type=\"text/css\" media=\"".$group."\" />\n"; } } else if ($type == 'js') { $output .= "\n"; } return $output; } /** * Load the config values of the CSS componente **/ private function _load_css_config() { if ($this->csstidy_loaded) return; $this->enable_csstidy = $this->CI->config->item('alp_enable_csstidy'); if ($this->enable_csstidy === TRUE) { $this->csstidy_loaded = TRUE;echo 'ss'; $csstidy = BASEPATH.$this->CI->config->item('alp_csstidy_basepath')."class.csstidy.php"; if (file_exists($csstidy)) require_once($csstidy); if (class_exists('csstidy')) $this->csstidy = new csstidy(); $this->csstidy->load_template($this->CI->config->item('alp_csstidy_template')); if ($this->enable_csstidy === TRUE) $csstidy_config = $this->CI->config->item('alp_csstidy_config'); foreach ($csstidy_config as $key => $val) $this->csstidy->set_cfg($key, $val); $this->gzip_compress_css = $this->CI->config->item('alp_gzip_compress_css'); } } /** * Load the config values of the JS componente **/ private function _load_js_config() { if ($this->jsmin_loaded) return; $this->enable_jsmin = $this->CI->config->item('alp_enable_jsmin'); if ($this->enable_jsmin === TRUE) { $this->jsmin_loaded = TRUE;echo 'ss'; $jsmin = BASEPATH.$this->CI->config->item('alp_jsmin'); if (file_exists($jsmin)) require_once($jsmin); $this->gzip_compress_js = $this->CI->config->item('alp_gzip_compress_js'); $this->force_cache_js = $this->CI->config->item('alp_force_cache_js'); } } /** * Delete old cache files in a directory * @param Path of directory * @param Type of cache (either 'css' or 'js') * @param String for matching file names **/ private function _unlink_old_caches($cache_dir, $new_file) { if ( ! @is_dir($cache_dir)) { return FALSE; } $new_file = explode('_',substr($new_file,0,strrpos($new_file,'.'))); //Days after which files with no read accesses get deleted: $delete_unread_after = 1; if ($handle = opendir($cache_dir)) { while (FALSE !== ($file = readdir($handle))) { //Ignore items starting with '.' if (strncasecmp($file,'.',1)) { //If it's a file and matches the criteria, then add it to the array if (is_file($cache_dir.'/'.$file)) { if (strpos($file,(implode('_',array($new_file[0],$new_file[1],$new_file[2])))) === 0) { unlink($cache_dir.'/'.$file); } else { $days_in_seconds = $delete_unread_after * 60 * 60 * 24; if ((fileatime($cache_dir.'/'.$file) + $days_in_seconds) < time() ) { unlink($cache_dir.'/'.$file); } } } } } closedir($handle); } } /** * Prevents url() references fom inside CSS files from breaking. * @param Name of group to fix files of **/ function _fix_css_urls($group) { foreach ($this->_assets['css'][$group] as $css_path => $code) { preg_match_all("/url\((?P.*?)\)/is", $code, $matches); if (!empty($matches['urls'])) { $urls = array(); foreach ($matches['urls'] as $old_url) { $old_url = trim($old_url,'"\''); if (strlen($old_url[1]) > 7 && strcasecmp(substr($old_url[1], 0, 7), 'http://') == 0) { $new_url = $old_url; } else { $new_url = dirname($css_path).'/'.$old_url; } $urls[$old_url] = $this->relative_path_to(str_replace(dirname(FCPATH),'',trim($this->cache_dir_css)).'/', $new_url); } $this->_assets['css'][$group][$css_path] = str_replace(array_keys($urls), array_values($urls), $code); } } } /** * Relative Path * * Find relative path from one file to the other * * @access public * @param string the first URL (subject) * @param string the first URL (object) * @return string */ function relative_path_to($from_file, $to_file) { // function author: name unknown (http://raribusment.com) // license: "Creative Commons Attribution-Share Alike 2.0 Generic" (http://creativecommons.org/licenses/by-sa/2.0/) // original source: http://raribusment.com/coding/relativepath/ // what separator are we using? // remember to check strpos with === $separator = '/'; $from_file = str_replace("\\", "/", $from_file); $to_file = str_replace("\\", "/", $to_file); // if ((strpos($from_file, $separator)===false) && // (strpos($to_file, $separator)===false)) { // // $separator = "\\"; // for windows systems is \ // } // we split the paths in pieces $from_file_pieces = explode($separator, $from_file); $to_file_pieces = explode($separator, $to_file); // pieces in common $i = 0; while (strcmp($from_file_pieces[$i], $to_file_pieces[$i]) == 0) { $i++; } $pieces_in_common = $i; // number of pieces each path $from_file_pieces_length = count($from_file_pieces); $to_file_pieces_length = count($to_file_pieces); // folders up/down. We substract one -> the last piece is a file, not a folder $folders_down = $from_file_pieces_length - $pieces_in_common - 1; // from -> root $folders_up = $to_file_pieces_length - $pieces_in_common -1; // root -> to // folders down: from -> root $relative_path_folders_down = ''; // hanging from the same folder if ( $folders_down == 0 && $folders_up == 0 ) { // do nothing, $relative_path_folders_down is already null } // second file hangs in a subdirectory of the first file else if ( $folders_down == 0 && $folders_up != 0 ) { $relative_path_folders_down = $separator; } else { for ($i = 0; $i<$folders_down; $i++) { $relative_path_folders_down .= '..'.$separator; } } // folders up: root -> to $relative_path_folders_up = ''; $to_last_folder = $pieces_in_common + $folders_up; for ($i = $pieces_in_common; $i<$to_last_folder; $i++) { $relative_path_folders_up .= $to_file_pieces[$i].$separator; } // we add the file $relative_path_folders_up .= $to_file_pieces[$to_last_folder]; return $relative_path_folders_down.$relative_path_folders_up; } /** * Set the headers to be sent in the javascript and css files * @param Type of asset file (either 'css' or 'js') * @param Whether to gzip asset * @param Whether to set a far-future caching expiration date to ensure optimal caching **/ private function _http_headers($type = '', $gzip_compress = FALSE, $far_future_expire = TRUE) { if ($type === 'css') $mime_type = 'css'; else if ($type === 'js') $mime_type = 'javascript'; else return FALSE; $php_header = ""; if ($gzip_compress) { $php_header = '= 1000) { header("Content-Encoding: gzip"); return $compressed_out; } else { return $output; } } if (strstr($HTTP_SERVER_VARS["HTTP_ACCEPT_ENCODING"], "gzip")) ob_start("gzip_compress"); ?>'; } if ($far_future_expire) { //When will the file expire? $offset = 6000000 * 60 ; $ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset)." GMT"; $php_header .= ''; } return $php_header; } } ?>