/** * CSS Magic actions in style.php. */ public function css_magic($cssIn) { global $phpbb_root_path, $phpEx, $wpUnited, $phpbbForum; define('WPU_STYLE_FIXER', true); require $phpbb_root_path . 'includes/hooks/hook_wp-united.' . $phpEx; if (!isset($wpUnited) || !$wpUnited->is_enabled()) { return $cssIn; } require_once $wpUnited->get_plugin_path() . 'functions-css-magic.php'; $wpuCache = WPU_Cache::getInstance(); if (!isset($_GET['usecssm'])) { return $cssIn; } $pos = request_var('pos', 'outer') == 'inner' ? 'inner' : 'outer'; $islandBlock = request_var('island', 0) == 1; $cacheLocation = ''; $tvFailed = false; $cssIdentifier = request_var('cloc', 0); $cssIdentifier = $wpUnited->get_style_key($cssIdentifier); $useTV = -1; if (isset($_GET['tv']) && $pos == 'inner') { $useTV = request_var('tv', -1); } /** * First check cache */ $css = ''; if ($useTV > -1) { // template voodoo-modified CSS already cached? if ($cacheLocation = $wpuCache->get_css_magic($cssIdentifier, $pos, $useTV, $islandBlock)) { $css = @file_get_contents($cacheLocation); } } else { // Try loading CSS-magic-only CSS from cache if ($cacheLocation = $wpuCache->get_css_magic($cssIdentifier, $pos, -1, $islandBlock)) { $css = @file_get_contents($cacheLocation); } } if (!empty($css)) { return $css; } // Apply or load css magic include $wpUnited->get_plugin_path() . 'css-magic.php'; $packagePath = $wpUnited->get_setting('phpbb_path'); $packageUrl = $phpbbForum->get_board_url(); $processImports = !($useTV > -1); $cssMagic = new CSS_Magic($processImports, $packageUrl, $packagePath); if (!$cssMagic->parseString($cssIn)) { return $cssIn; } // if pos= outer, we just need to cache the CSS so that Template Voodoo can get at it if ($pos == 'inner') { // Apply Template Voodoo if ($useTV > -1) { if (!apply_template_voodoo($cssMagic, $useTV)) { // set useTV to -1 so that cache name reflects that we weren't able to apply TemplateVoodoo $useTV = -1; $tvFailed = true; } } // Apply CSS Magic $cssMagic->makeSpecificByIdThenClass('wpucssmagic', false); } if ($islandBlock) { $cssMagic->makeSpecificByClass('wpuisle2', false); $cssMagic->makeSpecificByClass('wpuisle', false); } $desc = $pos == 'inner' ? 'modified to make it more specific' : 'parsed and cached so the style fixer can read it'; $now = date("F j, Y, g:i a"); $preHeader = <<<COUT /** \tThis CSS Stylesheet has been parsed with WP-United. The source is phpBB's style.php. \t-------------------------------------------------------------------------- \tThe CSS in this file has been {$desc}. \tYou should refer to the original CSS files for the underlying style rules. \tPurge the phpBB cache to re-generate this CSS. \tDate/Time generated: {$now} \t \tWP-United (c) John Wells, licensed under the GNU GPL v2. Underlying CSS copyright not affected. **/\t COUT; $css = $preHeader . $cssMagic->getCSS(); $cssMagic->clear(); //cache fixed CSS if (!$tvFailed) { $wpuCache->save_css_magic($css, $cssIdentifier, $pos, $useTV, $islandBlock); } return $css; }
/** * CSS MAGIC * * We now have properly separated inner/outer content * * We now identify all the stylesheets and redirect them to CSS Magic. * We don't parse them now, as style.php is used for phpBB styles. * * Once they have been parsed by CSS Magic, on subsequent run-throughs here, * we can read CSS Magic's cache and look at the stylesheets for conflicting * classes and IDs. Then, we modify the templates accordingly, and instruct CSS Magic * to make additional changes to the CSS the next time around. */ function wpu_css_magic() { global $wpUnited; $wpuCache = WPU_Cache::getInstance(); /** * Get all links to stylesheets, and prepare appropriate replacement links to insert into the page content * The generated CSS links to insert into the HTML will need to carry information for the browser on the * physical disk location of the CSS files on the server. * * We cannot allow browsers to just request any file on the server by filename, so get_stylesheet_links pre-approves the * files and stores them in the DB under "style keys". Browsers then only need to know the * appropriate style key, not the filename */ $innerSSLinks = wpu_get_stylesheet_links($wpUnited->get_inner_headinfo(), 'inner'); // also grep all inline css out of headers $inCSSInner = wpu_extract_css($wpUnited->get_inner_headinfo()); /** * Template Voodoo */ if ($wpUnited->get_setting('templateVoodoo')) { //For template voodoo, we also need the outer styles $outerSSLinks = wpu_get_stylesheet_links($wpUnited->get_outer_content(), 'outer'); $inCSSOuter = wpu_extract_css($wpUnited->get_outer_content()); // First check if the cached CSS Magic files exist, and insert placeholders for TV cache location if they do $foundInner = array(); $foundOuter = array(); foreach ((array) $innerSSLinks['keys'] as $index => $key) { if ($found = $wpuCache->get_css_magic($wpUnited->get_style_key($key), 'inner', -1)) { $foundInner[] = $found; $innerSSLinks['replacements'][$index] .= '[*FOUND*]'; } else { $innerSSLinks['replacements'][$index] .= '-1'; } } foreach ($outerSSLinks['keys'] as $index => $key) { if ($found = $wpuCache->get_css_magic($wpUnited->get_style_key($key), 'outer', -1)) { $foundOuter[] = $found; } } /** * Now we create a unique hash based on everything we've found, and use this to * store our Template Voodoo instructions. * We append the template voodoo hash key to the end of the redirected stylesheets */ $tplVoodooKey = $wpuCache->get_template_voodoo_key(TEMPLATEPATH, $foundInner, $foundOuter, (array) $inCSSInner['orig'], (array) $inCSSOuter['orig']); $innerSSLinks['replacements'] = str_replace('[*FOUND*]', $tplVoodooKey, $innerSSLinks['replacements']); if ((sizeof($foundInner) || $inCSSInner['orig']) && (sizeof($foundOuter) || $inCSSOuter['orig'])) { $classDupes = array(); $idDupes = array(); if ($templateVoodoo = $wpuCache->get_template_voodoo($tplVoodooKey)) { /** * The template voodoo instructions already exist for this CSS combination */ if (isset($templateVoodoo['classes']) && isset($templateVoodoo['ids'])) { $classDupes = $templateVoodoo['classes']; $idDupes = $templateVoodoo['ids']; } } else { /** * We don't have template voodoo for this yet, we need to do some legwork * and generate a set of instructions. * @todo move to separate function, generate_instructions(). */ $outerCSS = new CSS_Magic(); $innerCSS = new CSS_Magic(); foreach ($foundInner as $index => $cacheFile) { $innerCSS->parseFile($cacheFile); } foreach ($foundOuter as $index => $cacheFile) { $outerCSS->parseFile($cacheFile); } foreach ($inCSSInner['css'] as $index => $css) { $innerCSS->parseString($css); } foreach ($inCSSOuter['css'] as $index => $css) { $outerCSS->parseString($css); } $innerCSS->removeCommonKeyEl('#wpucssmagic .wpucssmagic'); $ignores = array('wpucssmagic', 'wpuisle'); $innerKeys = $innerCSS->getKeyClassesAndIDs(); $outerKeys = $outerCSS->getKeyClassesAndIDs($ignores); $innerCSS->clear(); $outerCSS->clear(); unset($innerCSS, $outerCSS); $classDupes = array_intersect($innerKeys['classes'], $outerKeys['classes']); $idDupes = array_intersect($innerKeys['ids'], $outerKeys['ids']); unset($innerKeys, $outerKeys); // save to cache $wpuCache->save_template_voodoo(array('classes' => $classDupes, 'ids' => $idDupes), $tplVoodooKey); } /** * Now, we can modify the page, removing class and ID duplicates from the inner content */ foreach ($classDupes as $dupe) { $findClass = substr($dupe, 1); //remove leading '.' $wpUnited->set_inner_content(preg_replace('/(class=["\']([^\\s^\'^"]*\\s+)*)' . $findClass . '([\\s\'"])/', '\\1wpu' . $findClass . '\\3', $wpUnited->get_inner_content())); } foreach ($idDupes as $dupe) { $findId = substr($dupe, 1); //remove leading '.' $wpUnited->set_inner_content(preg_replace('/(id=["\']\\s*)' . $findId . '([\\s\'"])/', '\\1wpu' . $findId . '\\2', $wpUnited->get_inner_content())); } } } // end template voodoo /** * Now we can apply the CSS magic to any inline CSS */ $useTVStr = $wpUnited->get_setting('templateVoodoo') ? 'TV' : ''; $tvKey = $wpUnited->get_setting('templateVoodoo') ? $tplVoodooKey : -1; $numFixes = 0; foreach ($inCSSInner['css'] as $index => $innerCSSItem) { if ($inlineCache = $wpuCache->get_css_magic("{$index}-{$useTVStr}", 'inline', $tvKey)) { $result = @file_get_contents($inlineCache); } else { $cssM = new CSS_Magic(); $cssM->parseString($innerCSSItem); /** * @todo could split out to templatevoodoo file */ if ($wpUnited->get_setting('templateVoodoo')) { if (isset($classDupes) && isset($idDupes)) { $finds = array(); $repl = array(); foreach ($classDupes as $classDupe) { $finds[] = $classDupe; $repl[] = ".wpu" . substr($classDupe, 1); } foreach ($idDupes as $idDupe) { $finds[] = $idDupe; $repl[] = "#wpu" . substr($idDupe, 1); } $cssM->modifyKeys($finds, $repl); } } $cssM->makeSpecificByIdThenClass('wpucssmagic', false); $result = $cssM->getCSS(); // save to cache $wpuCache->save_css_magic($result, "{$index}-{$useTVStr}", 'inline', $tvKey); } if (!empty($result)) { //$result = '<style type="text/css">' . $result . '</style>'; $wpUnited->set_inner_headinfo(str_replace($inCSSInner['orig'][$index], $result, $wpUnited->get_inner_headinfo())); $numFixes++; } } // Store the updated style keys $wpUnited->commit_style_keys(); // add link to reset stylesheet $reset = "<link href=\"{$wpUnited->get_plugin_url()}theme/reset.css\" rel=\"stylesheet\" media=\"all\" type=\"text/css\" />"; $wpUnited->set_inner_headinfo($reset . $wpUnited->get_inner_headinfo()); //write out the modified stylesheet links $wpUnited->set_inner_headinfo(str_replace($innerSSLinks['links'], $innerSSLinks['replacements'], $wpUnited->get_inner_headinfo())); if ($wpUnited->get_setting('templateVoodoo')) { $wpUnited->set_outer_content(str_replace($outerSSLinks['links'], $outerSSLinks['replacements'], $wpUnited->get_outer_content())); } /** * Elements (mainly third-party BBCodes) with height="" cannot override the height CSS rule set in CSS Magic's reset.css * This adds an inline CSS style attribute to any such elements * If the element already has an inline style attribute, the height rule will be appended to it */ $withInline = preg_replace_callback('/((<[^>]+\\b)(?=height\\s?=\\s?[\'"]?\\s?([0-9]+)\\s?[\'"]?)([^>]*?))(\\/?\\s*>)/', create_function('$m', 'if(preg_match(\'/(style\\s?=\\s?[\\\'"]([^\\\'"]+))([\\\'"])/\', $m[1], $r)) return str_replace($r[0], "{$r[1]};height:{$m[3]}px;{$r[3]}", $m[1]) . $m[5]; return $m[1] . \' style="height:\' . $m[3] . \'px;" \' . $m[5];'), $wpUnited->get_inner_content()); //same with width $withInline = preg_replace_callback('/((<[^>]+\\b)(?=width\\s?=\\s?[\'"]?\\s?([0-9]+)\\s?[\'"]?)([^>]*?))(\\/?\\s*>)/', create_function('$m', 'if(preg_match(\'/(style\\s?=\\s?[\\\'"]([^\\\'"]+))([\\\'"])/\', $m[1], $r)) return str_replace($r[0], "{$r[1]};width:{$m[3]}px;{$r[3]}", $m[1]) . $m[5]; return $m[1] . \' style="width:\' . $m[3] . \'px;" \' . $m[5];'), $withInline); //and bgcolor $withInline = preg_replace_callback('/((<[^>]+\\b)(?=bgcolor\\s?=\\s?[\'"]?\\s?([0-9]+)\\s?[\'"]?)([^>]*?))(\\/?\\s*>)/', create_function('$m', 'if(preg_match(\'/(style\\s?=\\s?[\\\'"]([^\\\'"]+))([\\\'"])/\', $m[1], $r)) return str_replace($r[0], "{$r[1]};background-color:{$m[3]}px;{$r[3]}", $m[1]) . $m[5]; return $m[1] . \' style="background-color:\' . $m[3] . \'px;" \' . $m[5];'), $withInline); $wpUnited->set_inner_content($withInline); }
/** * Parses inbound CSS, storing it as an internal representation of keys and code * @param string $str A valid CSS string * @return int the number of CSS keys stored */ public function parseString($str, $clear = false) { if ($clear) { $this->clear(); } $keys = ''; $Instr = $str; // Remove comments $str = preg_replace("/\\/\\*(.*)?\\*\\//Usi", "", $str); $str = str_replace("\t", "", $str); $str = str_replace("}\\", '[TANTEK]', $str); // find nested stylesheets preg_match_all('/(\\@[^\\{]*\\{)([^\\{^\\}]*(\\{[^\\@^\\{^\\}]*\\}[^\\{^\\}]*)*?)\\}/', $str, $nested); $nestIndex = sizeof($this->nestedItems); if (sizeof($nested[0]) && isset($nested[1]) && is_array($nested[1]) && sizeof($nested[1])) { foreach ($nested[1] as $nestNum => $nestSel) { if (!empty($nestSel) && isset($nested[2]) && is_array($nested[2]) && isset($nested[2][$nestNum])) { // handle imported stylesheets separately if (stristr($nestSel, '@import') !== false) { continue; } $subSheet = new CSS_Magic($this->processImports, $this->baseUrl, $this->basePath); $subSheet->set_filename($this->filename); $this->totalItems = $this->totalItems + $subSheet->parseString($nested[2][$nestNum]); $this->nestedItems[$nestIndex] = array('selector' => $nestSel, 'content' => $subSheet); $str = str_replace($nested[0][$nestNum], '[WPU_NESTED] {' . $nestIndex . '}', $str); $nestIndex++; } } } // Other nested stylesheets: if ($this->processImports) { preg_match_all('/\\@import\\s(url\\()?[\'"]?([^\'^"^\\)]*)[\'"]?\\)?;/', $str, $imported); $importIndex = sizeof($this->importedItems); if (sizeof($imported[0]) && isset($imported[2]) && is_array($imported[2]) && sizeof($imported[2])) { foreach ($imported[2] as $importNum => $importUrl) { $this->totalItems = $this->totalItems + 1; $subSheet = new CSS_Magic($this->processImports, $this->baseUrl, $this->basePath); $this->importedItems[$importIndex] = array('obj' => $subSheet, 'orig' => $imported[0][$importNum], 'url' => $imported[2][$importNum]); $str = str_replace($imported[0][$importNum], '[WPU_NESTED_IMPORT] {' . $importIndex . '}', $str); $importIndex++; } } // Now process the nested imports: $this->process_imports($subUrl, $subPath); } $parts = explode("}", $str); if (count($parts) > 0) { foreach ($parts as $part) { if (strpos($part, '{') !== FALSE) { list($keys, $cssCode) = explode('{', $part); // store full selector if (strlen($keys) > 0) { $keys = str_replace("\n", "", $keys); $keys = str_replace("\r", "", $keys); $keys = str_replace("\\", "", $keys); $this->addSelector($keys, trim($cssCode)); } } } } // process nested stylesheets too $this->totalItems = $this->totalItems + count($this->css); return $this->totalItems; }