* Copyright 2001-2012 Strangecode, LLC * * This file is part of The Strangecode Codebase. * * The Strangecode Codebase is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your option) * any later version. * * The Strangecode Codebase is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * The Strangecode Codebase. If not, see . */ /** * CSS.inc.css * * Dynamically outputs cached CSS data. * * @author Quinn Comendant * @version 1.2 */ class CSS { // Include these style sheets. protected $_css_files = array('default' => array()); // CSS object parameters. protected $_params = array( 'character_set' => 'utf-8', 'cache_enable' => false, 'cache_css' => null, // Same as above; kept for backwards compatibility. 'cache_seconds' => 7776000, // 90 days. 'strip_whitespace' => false, 'output_compression' => false, ); /** * Set (or overwrite existing) parameters by passing an array of new parameters. * * @access public * @param array $params Array of parameters (key => val pairs). */ public function setParam($params) { $app =& App::getInstance(); if (isset($params) && is_array($params)) { // Merge new parameters with old overriding only those passed. $this->_params = array_merge($this->_params, $params); // Maintaining backwards compatibility. if (isset($params['cache_css']) && !isset($params['cache_enable'])) { $this->_params['cache_enable'] = $params['cache_css']; } } else { $app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_ERR, __FILE__, __LINE__); } } /** * Return the value of a parameter, if it exists. * * @access public * @param string $param Which parameter to return. * @return mixed Configured parameter value. */ public function getParam($param) { $app =& App::getInstance(); if (array_key_exists($param, $this->_params)) { return $this->_params[$param]; } else { $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__); return null; } } /** * Add a file-path to the array of files to include as CSS. * * @access public * @param string $file Include path to css files. * @param mixed $realms Realm name string or array of realm names. * @return bool True on success, false on failure. */ public function setFile($file, $realms='') { $app =& App::getInstance(); if (!is_array($realms)) { $realms = array($realms); } if ($fp = fopen($file, 'r', true)) { foreach ($realms as $realm) { $realm = '' == $realm ? 'default' : $realm; $this->_css_files[$realm][] = $file; } fclose($fp); return true; } else { $app->logMsg(sprintf('CSS file non-existent: %s', $file), LOG_ERR, __FILE__, __LINE__); return false; } } /** * Output headers for CSS. * * @access public * * @return bool False if no files have been set. */ public function headers($realm='') { $app =& App::getInstance(); $realm = '' == $realm ? 'default' : $realm; if (empty($this->_css_files[$realm])) { $app->logMsg(sprintf('CSS::headers called without specifying any files.', null), LOG_WARNING, __FILE__, __LINE__); return false; } // Get time of latest modified file, including this class file. $files_mtime = array(); foreach (array_merge($this->_css_files[$realm], array(__FILE__)) as $file) { $files_mtime[] = statIncludePath($file, 'mtime'); } sort($files_mtime, SORT_NUMERIC); $latest_mtime = array_pop($files_mtime); if ($this->getParam('output_compression') && extension_loaded('zlib')) { ob_start('ob_gzhandler'); } header(sprintf('Content-Type: text/css; charset=%s', $this->getParam('character_set'))); header(sprintf('Last-Modified: %s GMT', gmdate('D, d M Y H:i:s', $latest_mtime), null)); if ($this->getParam('cache_enable')) { header(sprintf('Cache-Control: public, max-age=%s', $this->getParam('cache_seconds'))); header(sprintf('Expires: %s GMT', gmdate('D, d M Y H:i:s', $latest_mtime + $this->getParam('cache_seconds')))); header('Pragma: public'); header('Vary: Accept-Encoding'); } else { // Disallow HTTP caching entirely. http://stackoverflow.com/a/2068407 header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. header('Pragma: no-cache'); // HTTP 1.0. header('Expires: 0'); // Proxies. } } /** * Include CSS files specified by setFile(). * * @access public * * @return bool False if no files have been set. */ public function output($realm='') { $app =& App::getInstance(); $realm = '' == $realm ? 'default' : $realm; if (empty($this->_css_files[$realm])) { $app->logMsg(sprintf('CSS::output called without specifying any files.', null), LOG_WARNING, __FILE__, __LINE__); return false; } foreach ($this->_css_files[$realm] as $file) { if ($this->getParam('strip_whitespace')) { // Strip whitespace and print file. echo preg_replace( array('!/\*.*?\*/!s' . $app->getParam('preg_u'), '/[\n\r]+/' . $app->getParam('preg_u'), '/([;:])\s+/m' . $app->getParam('preg_u'), '/\s*}[ \t]*/' . $app->getParam('preg_u'), '/\s*{\s*/' . $app->getParam('preg_u'), '/[ \t\n\r]*,[ \t\n\r]*/' . $app->getParam('preg_u'), '/^\s+/' . $app->getParam('preg_u')), array('', "\n", '$1', '}', '{', ',', ''), file_get_contents($file, true) ); } else { // Include file as is. include $file; } } if ($this->getParam('output_compression') && extension_loaded('zlib')) { ob_end_flush(); } } }