/** * Imports css via @import statements * * @author Anthony Short * @param $css */ public static function server_import($css, $base) { if (preg_match_all('/\\@include\\s+(?:\'|\\")([^\'\\"]+)(?:\'|\\")\\;/', $css, $matches)) { $unique = array_unique($matches[1]); $include = str_replace("\\", "/", Scaffold_Utils::unquote($unique[0])); # If they haven't supplied an extension, we'll assume its a css file if (pathinfo($include, PATHINFO_EXTENSION) == "") { $include .= '.css'; } # Make sure it's a CSS file if (pathinfo($include, PATHINFO_EXTENSION) != 'css') { $css = str_replace($matches[0][0], '', $css); Scaffold::log('Invalid @include file - ' . $include); self::server_import($css, $base); } # Find the file if ($path = Scaffold::find_file($include, $base)) { # Make sure it hasn't already been included if (!in_array($path, self::$loaded)) { self::$loaded[] = $path; $contents = file_get_contents($path); # Check the file again for more imports $contents = self::server_import($contents, realpath(dirname($path)) . '/'); $css = str_replace($matches[0][0], $contents, $css); } else { $css = str_replace($matches[0][0], '', $css); } } else { Scaffold::error('Can\'t find the @include file - <strong>' . $unique[0] . '</strong>'); } $css = self::server_import($css, $base); } return $css; }
/** * Parse the CSS. This takes an array of files, options and configs * and parses the CSS, outputing the processed CSS string. * * @param array List of files * @param array Configuration options * @param string Options * @param boolean Return the CSS rather than displaying it * @return string The processed css file as a string */ public static function parse($files, $config, $options = array(), $display = false) { # Benchmark will do the entire run from start to finish Scaffold_Benchmark::start('system'); try { # Setup the cache and other variables/constants Scaffold::setup($config); self::$options = $options; $css = false; # Time it takes to get the flags Scaffold_Benchmark::start('system.flags'); # Get the flags from each of the loaded modules. $flags = self::$flags === false ? array() : self::flags(); # Time it takes to get the flags Scaffold_Benchmark::stop('system.flags'); # The final, combined CSS file in the cache $combined = md5(serialize(array($files, $flags))) . '.css'; /** * Check if we should use the combined cache right now and skip unneeded processing */ if (SCAFFOLD_PRODUCTION === true and Scaffold_Cache::exists($combined) and Scaffold_Cache::is_fresh($combined)) { Scaffold::$output = Scaffold_Cache::open($combined); } if (Scaffold::$output === null) { # We're processing the files Scaffold_Benchmark::start('system.check_files'); foreach ($files as $file) { # The time to process a single file Scaffold_Benchmark::start('system.file.' . basename($file)); # Make sure this file is allowed if (substr($file, 0, 4) == "http" or substr($file, -4, 4) != ".css") { Scaffold::error('Scaffold cannot the requested file - ' . $file); } /** * If there are flags, we'll include them in the filename */ if (!empty($flags)) { # Webligo PHP5.1 compat $cached_file = dirname($file) . DIRECTORY_SEPARATOR . substr(basename($file), 0, strrpos(basename($file), '.')) . '_' . implode('_', $flags) . '.css'; # $cached_file = dirname($file) . DIRECTORY_SEPARATOR . pathinfo($file, PATHINFO_FILENAME) . '_' . implode('_', $flags) . '.css'; } else { $cached_file = $file; } $request = Scaffold::find_file($file, false, true); /** * While not in production, we want to to always recache, so we'll fake the time */ $modified = SCAFFOLD_PRODUCTION ? Scaffold_Cache::modified($cached_file) : 0; /** * If the CSS file has been changed, or the cached version doesn't exist */ if (!Scaffold_Cache::exists($cached_file) or $modified < filemtime($request)) { Scaffold_Cache::write(Scaffold::process($request), $cached_file); Scaffold_Cache::remove($combined); } $css .= Scaffold_Cache::open($cached_file); # The time it's taken to process this file Scaffold_Benchmark::stop('system.file.' . basename($file)); } Scaffold::$output = $css; /** * If any of the files have changed we need to recache the combined */ if (!Scaffold_Cache::exists($combined)) { Scaffold_Cache::write(self::$output, $combined); } # The time it takes to process the files Scaffold_Benchmark::stop('system.check_files'); /** * Hook to modify what is sent to the browser */ if (SCAFFOLD_PRODUCTION === false) { Scaffold::hook('display'); } } /** * Set the HTTP headers for the request. Scaffold will set * all the headers required to score an A grade on YSlow. This * means your CSS will be sent as quickly as possible to the browser. */ $length = strlen(Scaffold::$output); $modified = Scaffold_Cache::modified($combined); $lifetime = SCAFFOLD_PRODUCTION === true ? $config['cache_lifetime'] : 0; Scaffold::set_headers($modified, $lifetime, $length); /** * If the user wants us to render the CSS to the browser, we run this event. * This will send the headers and output the processed CSS. */ if ($display === true) { Scaffold::render(Scaffold::$output, $config['gzip_compression']); } # Benchmark will do the entire run from start to finish Scaffold_Benchmark::stop('system'); } catch (Exception $e) { /** * The message returned by the error */ $message = $e->getMessage(); /** * Load in the error view */ if (SCAFFOLD_PRODUCTION === false && $display === true) { Scaffold::send_headers(); require Scaffold::find_file('scaffold_error.php', 'views'); } } # Log the final execution time #$benchmark = Scaffold_Benchmark::get('system'); #Scaffold_Log::log('Total Execution - ' . $benchmark['time']); # Save the logs and exit Scaffold_Event::run('system.shutdown'); return self::$output; }
/** * Replaces all of the constants in a CSS string * with the constants defined in the member variable $constants * using PHP's interpolation. */ public static function replace($css) { // START - Modified by Webligo Developments # Strip SVN Keywords $css = preg_replace('/[$][a-z]+?[:].+?[$]/i', '', $css); //preg_match('/[$][a-z]+?[:].+?[$]/i', $css, $m); // END - Modified by Webligo Developments # Pull the constants into the local scope as variables extract(self::$constants, EXTR_SKIP); # Remove unset variables from the string, so errors aren't thrown foreach (array_unique(Scaffold_Utils::match('/\\{?\\$([A-Za-z0-9_-]+)\\}?/', $css, 1)) as $value) { if (!isset(${$value})) { Scaffold::error('Missing constant - ' . $value); } } $css = stripslashes(eval('return "' . addslashes($css) . '";')); # Replace the variables within the string like a normal PHP string return $css; }
/** * Loads each of the property functions and parses them. * * @param $name The location of the extension files * @param $function The CSS function to call to look for instances of it in the CSS * @param $split_params Explode the params before sending them off to the user function * @return $css string */ public static function load_extensions($location, $function, $split_params = false) { $files = Scaffold::list_files($location, true); foreach ($files as $path) { if (is_dir($path)) { continue; } /** * If the functions or properties ARE unique, they will * be parsed as such. If not, properties or functions that * are found to be exactly the same will be merged. */ $unique = false; /** * The name of the property that can be used in Scaffold CSS */ # Webligo PHP5.1 compat $extension_name = substr(basename($path), 0, strrpos(basename($path), '.')); #$extension_name = pathinfo($path, PATHINFO_FILENAME); /** * Include the function we'll use as a callback */ if (!isset(self::$extensions[$extension_name])) { include_once $path; } else { $unique = self::$extensions[$extension_name]['unique']; } /** * The name of the function we'll call for this property */ $callback = 'Scaffold_' . str_replace('-', '_', $extension_name); /** * Save this extension */ self::$extensions[$extension_name] = array('unique' => $unique, 'path' => $path, 'callback' => $callback, 'function' => $function, 'split_params' => $split_params); /** * Find an replace them */ if ($found = Scaffold::$css->{$function}($extension_name)) { // Make the list unique or not $originals = $unique === false ? array_unique($found[0]) : $found[0]; // Loop through each found instance foreach ($originals as $key => $value) { // Explode the params to send them as function params or as a single param if ($split_params === true) { $result = call_user_func_array($callback, explode(',', $found[2][$key])); } else { $result = call_user_func($callback, $found[2][$key]); } // Run the user callback if ($result === false) { Scaffold::error('Invalid Extension Syntax - <strong>' . $originals[$key] . '</strong>'); } elseif ($unique === true) { $pos = strpos(Scaffold::$css->string, $originals[$key]); if ($pos !== false) { Scaffold::$css->string = substr_replace(Scaffold::$css->string, $result, $pos, strlen($originals[$key])); } } else { Scaffold::$css->string = str_replace($originals[$key], $result, Scaffold::$css->string); } } } } }
/** * Replaces all of the constants in a CSS string * with the constants defined in the member variable $constants * using PHP's interpolation. */ public static function replace($css) { # Pull the constants into the local scope as variables extract(self::$constants, EXTR_SKIP); # Remove unset variables from the string, so errors aren't thrown foreach (array_unique(Scaffold_Utils::match('/\\{?\\$([A-Za-z0-9_-]+)\\}?/', $css, 1)) as $value) { if (!isset(${$value})) { Scaffold::error('Missing constant - ' . $value); } } $css = stripslashes(eval('return "' . addslashes($css) . '";')); # Replace the variables within the string like a normal PHP string return $css; }
/** * Checks if all the needed settings are present in a group * * @param $group * @return boolean */ private static function check_grid($group, $settings) { if (!isset($settings['column-count'])) { Scaffold::error('Missing property from @grid - <strong>column-count</strong>'); } elseif (!isset($settings['baseline'])) { Scaffold::error('Missing property from @grid - <strong>baseline</strong>'); } elseif (!isset($settings['grid-width'])) { Scaffold::error('Missing property from @grid - <strong>grid-width</strong>'); } else { return true; } }