debugMode = $this->Application->isDebugMode(false); $this->infoFile = WRITEABLE . '/cache/compress_info.txt'; if ( file_exists($this->infoFile) ) { $this->compressInfo = unserialize( file_get_contents($this->infoFile) ); } } /** * When used as non-block tag, then compress given files and return url to result * * @param Array $files * @return string */ function CompressScriptTag($params) { // put to queue if (array_key_exists('to', $params)) { $files = $this->Application->GetVar($params['to'], ''); $this->Application->SetVar($params['to'], $files . '|' . $params['files']); return ''; } if (array_key_exists('from', $params)) { // get from queue $files = $this->Application->GetVar($params['from']); } else { // get from tag $files = $params['files']; } $files = $this->_getTemplatePaths( array_map('trim', explode('|', $files)) ); $extension = pathinfo($files[0], PATHINFO_EXTENSION); $hash = ($this->debugMode ? 'd' : 'c') . '_' . $this->_getHash($files); $file_mask = 'cache/' . $hash . '_%s.' . $extension; $was_compressed = array_key_exists($hash, $this->compressInfo); if ($was_compressed) { $current_file = WRITEABLE . '/' . sprintf($file_mask, $this->compressInfo[$hash]); if (!file_exists($current_file)) { // when info exists, but file doesn't -> re-compress $was_compressed = false; } if ($this->debugMode) { // check if any of listed files was changed since compressed file was created (only, when in debug mode) foreach ($files as $file) { if (filemtime($file) > $this->compressInfo[$hash]) { $was_compressed = false; break; } } } } if (!$was_compressed) { $string = ''; $path_length = strlen(FULL_PATH) + 1; foreach ($files as $file) { // add filename before for easier debugging if ($this->debugMode) { $string .= '/* === File: ' . substr($file, $path_length) . ' === */' . "\n"; $string .= '/* ' . str_repeat('=', strlen(substr($file, $path_length)) + 14) . ' */' . "\n\n"; } // add file content $string .= file_get_contents($file) . "\n\n"; } // remove previous version of compressed file if (isset($current_file)) { if (file_exists($current_file)) { unlink($current_file); } } // replace templates base $templates_base = $this->Application->ProcessParsedTag('m', 'TemplatesBase', Array ()); $templates_base = preg_replace('/^' . preg_quote($this->Application->BaseURL(), '/') . '/', BASE_PATH . '/', $templates_base); $string = str_replace('@templates_base@', rtrim($templates_base, '/'), $string); // compress collected data $this->compressInfo[$hash] = adodb_mktime(); if (!$this->debugMode) { // don't compress merged js/css file in debug mode to allow js/css debugging $this->compressString($string, $extension); } // save compressed file $fp = fopen(WRITEABLE . '/' . sprintf($file_mask, $this->compressInfo[$hash]), 'w'); fwrite($fp, $string); fclose($fp); $this->_saveInfo(); } // got compressed file -> use it return $this->Application->BaseURL( str_replace(DIRECTORY_SEPARATOR, '/', WRITEBALE_BASE)) . sprintf($file_mask, $this->compressInfo[$hash]); } /** * Returns hash string based on given files * * @param Array $files * @return int */ function _getHash($files) { $hash = $files; if ($this->Application->isAdmin) { array_unshift($hash, 'A:1'); } else { array_unshift($hash, 'A:0;T:' . $this->Application->GetVar('m_theme')); } return crc32( implode('|', $hash) ); } /** * Saves file with compress information * */ function _saveInfo() { $fp = fopen($this->infoFile, 'w'); fwrite($fp, serialize($this->compressInfo)); fclose($fp); } /** * Deletes compression info file * * @todo also delete all listed there files */ function delete() { if (file_exists($this->infoFile)) { unlink($this->infoFile); } } /** * Compress $string based on $extension * * @param string $string * @param string $extension */ function compressString(&$string, $extension) { $tmp_file = tempnam('/tmp', 'to_compress_'); $fp = fopen($tmp_file, 'w'); fwrite($fp, $string); fclose($fp); $command = 'java -jar ' . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'yuicompressor-2.4.2.jar --type ' . $extension . ' --charset utf-8 ' . $tmp_file; $compressed_string = shell_exec($command); unlink($tmp_file); if (!is_null($compressed_string) && $compressed_string) { $string = $compressed_string; return ; } // failed to compress using YUICompressor (maybe java not installed) if ($extension == 'js') { $minifier =& $this->Application->makeClass('JsMinifyHelper'); /* @var $minifier JsMinifyHelper */ $string = $minifier->minify($string); } elseif ($extension == 'css') { $minifier =& $this->Application->makeClass('CssMinifyHelper'); /* @var $minifier CssMinifyHelper */ $string = $minifier->minify($string); } } /** * Get full paths on disk for each of given templates * * @param Array $templates * @return Array */ function _getTemplatePaths($templates) { $ret = Array (); $reg_exp = '/^' . preg_quote($this->Application->BaseURL(), '/') . '(.*)/'; foreach ($templates as $template) { if (!$template) { continue; } if (preg_match($reg_exp, $template, $regs)) { // full url (from current domain) to a file $path = FULL_PATH . '/' . $regs[1]; } else { list ($path, $module_filename) = $this->Application->TemplatesCache->GetTemplatePaths($template); $path .= DIRECTORY_SEPARATOR . $module_filename; } $ret[] = $path; } return $ret; } }