array(), 'individualStylesheetPaths' => array(), 'stylesheet' => array(), 'script' => array(), ); protected static $_configLoaded = false; protected static $_configChanged = false; protected static function _getConfigFileName() { return WWW_PATH . '/_lib/packer.config.php'; } public static function loadConfig() { if (Qs_Packer::$_configLoaded) { return false; } $file = Qs_Packer::_getConfigFileName(); if (!file_exists($file)) { $content = " $href, 'attribs' => $options); continue; } if (!Qs_Packer::isRegisteredStylesheet($options['href'])) { Qs_Packer::registerStylesheet($options['href']); } $path = $_path = dirname($options['href']); $media = Qs_Array::get($options, 'media', 'screen'); $isIndividualPath = false; do { if (in_array($_path, Qs_Packer::$_config['individualStylesheetPaths'])) { $isIndividualPath = true; break; } } while ('.' != ($_path = dirname($_path)) && '/' != $_path); if (!$isIndividualPath) { $path = Qs_Packer::$_defaultStylesheetPath; } $itemIndex = $path . ':' . $media; if (!array_key_exists($itemIndex, $indexes)) { $indexes[$itemIndex] = array( 'path' => $path, 'media' => $media, 'indexes' => array(), ); } $indexes[$itemIndex]['indexes'][] = Qs_Packer::getStylesheetIndex($options['href']); } foreach ($indexes as $options) { $href = $options['path'] . '/' . implode('-', $options['indexes']) . Qs_Packer::_getSuffix() . '.merge.css'; $mergedStylesheets = array( // 1-st argument in doc->addStylesheet function 'href' => $href, // 2-nd argument in doc->addStylesheet function 'attribs' => array( 'media' => $options['media'] ) ); array_unshift($result, $mergedStylesheets); } Qs_Packer::updateConfig(); return $result; } public static function getMergedScripts($list) { if (empty($list)) { return false; } Qs_Packer::loadConfig(); $result = array(); $indexes = array(); foreach ($list as $options) { if (!Qs_Packer::_isLocalFile($options['src']) || Qs_Array::get($options, 'skipPacking', false)) { $result[] = $options['src']; continue; } if (!Qs_Packer::isRegisteredScript($options['src'])) { Qs_Packer::registerScript($options['src']); } $path = $_path = dirname($options['src']); $isIndividualPath = false; do { if (in_array($_path, Qs_Packer::$_config['individualScriptPaths'])) { $isIndividualPath = true; break; } } while ('.' != ($_path = dirname($_path))); if (!$isIndividualPath) { $path = Qs_Packer::$_defaultScriptPath; } $indexes[$path][] = Qs_Packer::getScriptIndex($options['src']); } foreach ($indexes as $path => $pathIndexes) { array_unshift($result, $path . '/' . implode('-', $pathIndexes) . Qs_Packer::_getSuffix(). '.merge.js'); } Qs_Packer::updateConfig(); return $result; } protected static function _isLocalFile($file) { // gag: parse_url does not support protocol related urls (https://bugs.php.net/bug.php?id=43721) if ('//' == substr($file, 0, 2)) { $file = 'http:' . $file; } $fileHost = parse_url($file, PHP_URL_HOST); if ($fileHost && $fileHost != parse_url(constant('BASE_URL'), PHP_URL_HOST)) { return false; } return true; } public static function merge($indexes, $file, $suffix, $extension) { if (empty($indexes)) { return false; } Qs_Packer::loadConfig(); switch ($extension) { case 'css': $files = Qs_Packer::$_config['stylesheet']; $delimiter = "\n"; break; case 'js': $files = Qs_Packer::$_config['script']; $delimiter = ";\n"; break; default: return false; } $list = array(); foreach ($indexes as $index) { if (array_key_exists($index, $files)) { $list[$index] = $files[$index]; if ($suffix == 'pack') { $list[$index] = str_replace('.' . $extension, '.' . $suffix . '.' . $extension, $list[$index]); } } } if (!$handle = fopen(WWW_PATH . '/' . $file, 'w+')) { return false; } foreach ($list as $name) { $content = file_get_contents(WWW_PATH . '/' . $name); if ('css' === $extension) { $content = self::_prepareCssResourcePaths($file, $name, $content); } fwrite($handle, $content . $delimiter); } fclose($handle); return true; } /** * Method replace related paths for resources inside css * @param string $dstFile Relative name of destination file (ex. css/0-1-2.merge.css) * @param string $srcFile Relative name of source file (ex. css/modules/site.css) * @param string $content Source file content * @return string * @throws Exception */ protected static function _prepareCssResourcePaths($dstFile, $srcFile, $content) { $dstPathDepth = (int) substr_count($dstFile, '/'); $pathDepth = (int)substr_count($srcFile, '/'); $pathDiff = $pathDepth - $dstPathDepth; if (0 > $pathDiff) { throw new Exception('Wrong location of resource file "' . $srcFile . '"'); } elseif (0 < $pathDiff) { $resourcePath = ($resourcePath = substr(dirname($srcFile), strlen('css/'))) ? $resourcePath : BASE_URL . '/' . dirname($srcFile); $content = preg_replace_callback( '#url\(\s*(([\'"])?([^\s\)]+)?\1?)\s*\)#', function ($match) use ($resourcePath) { $quote = $match[2]; $path = $match[1]; if (0 === strpos($path, 'data:')) { return $match[0]; } if ($quote) { $path = trim($path, $quote); } if (false !== strpos($path, '://') || '/' === $path[0]) { return $match[0]; } $path = $resourcePath . '/' . $path; return "url({$quote}{$path}{$quote})"; }, $content ); } return $content; } }