<? 
/** 
 * Object Oriented CSS 2.0 
 * September 5, 2009 
 * Corey Hart @ http://www.codenothing.com 
 * 
 * Credit to Thiemo Mättig @ http://maettig.com/ for his regex help 
 */  
 
 
Class ObjectOrientedCSS 
{ 
    /** 
     * Class Vars 
     * 
     * @param (array) vars: Holds variables found in css file 
     * @param (string) file: Contents of css file 
     * @param (array) tree: Holds parsed tree found in css file 
     */  
    var $vars = array(); 
    var $file = ''; 
    var $tree = array(); 
 
    /** 
     * Centralized function to run the OOCSS Parser 
     * 
     * @param (string) css: Contents of css file 
     */  
    function run($css){ 
        // Store contents into class var 
        $this->file = $css; 
 
        // Raw file trimmed down to single line 
        $this->trimCSS(); 
 
        // Run variable conversions first 
        $this->variableReplacement(); 
 
        // Loop through and create the tree (Pass file as var, for loop) 
        $this->prepFileForLoop(); 
        $this->tree = $this->convertLoop($this->file); 
 
        // Process tree for output (Pass as var, for loops) 
        $this->file = $this->processFile($this->tree); 
 
        // Return parsed file for quick output 
        return $this->file; 
    } 
 
    /** 
     * Format the css file into single line 
     * 
     * @params none 
     */  
    function trimCSS(){ 
        // Remove CSS Comments 
        $this->file = preg_replace("/\/\*(.*?)\*\//s", '', $this->file); 
        // Remove Multiple Spaces (Credit goes to Thiemo Mättig @ http://maettig.com/ for pointing out this regex) 
        $this->file = preg_replace("/\s+/s", ' ', $this->file); 
    } 
 
    /** 
     * Find and replace variables 
     * 
     * @params none 
     */  
    function variableReplacement(){ 
        // Credit goes to Thiemo Mättig @ http://maettig.com/ for pointing out this regex 
        preg_match_all("/([$]\w+)\s*=\s*([^;]+);/s", $this->file, $matches); 
        for ($i=0, $imax=count($matches[0]); $i<$imax; $i++){ 
            // Matches 
            $string = $matches[0][$i]; 
            $var = $matches[1][$i]; 
            $value = $matches[2][$i]; 
 
            // Check for multiple definitions 
            if (strpos($value, '{') !== false){ 
                $value = str_replace('{', '', $value); 
                $value = str_replace('}', '', $value); 
                $value = str_replace(',', ';', $value); 
            } 
 
            // Store the var for debugging 
            $this->vars[$var] = $value; 
 
            // Remove the declaration from the file 
            $this->file = str_replace($string, '', $this->file); 
 
            // Enforce semi-colon replacement 
            $this->file = str_replace($var.';', $value.';', $this->file); 
        } 
    } 
 
    /** 
     * Reformat css contents into seperate lines 
     * for line-by-line parsing 
     * 
     * @params none 
     */  
    function prepFileForLoop(){ 
        // Line out as much as possible 
        $this->file = preg_replace("/([{]|[}]|;)/", "$1\n", $this->file); 
 
        // Return each line 
        $this->file = explode("\n", str_replace('}', "\n}", $this->file)); 
    } 
 
    /** 
     * Create tree structure from formatted contents. 
     * Recursively calls itself to reach multiple levels 
     * 
     * @param (array) file: Reformated css contents 
     */  
    function convertLoop(&$file){ 
        $ret = $old = array(); 
        while ($file){ 
            $line = trim(array_shift($file)); 
            if (!$line || $line == ''){ 
                continue; 
            } 
            else if (strpos($line, '{') !== false){ 
                // Take out the tag 
                $tag = trim(array_shift(explode('{', $line))); 
 
                // Store old tag for merging 
                if (isset($ret[$tag])) 
                    $old = $ret; 
 
                // Run recursive loop of all levels 
                $ret[$tag] = $this->convertLoop($file); 
 
                // If old tag found, merge results 
                if ($old){ 
                    $ret = array_merge_recursive($old, $ret); 
                    $old = array(); 
                } 
            } 
            else if (strpos($line, '}') !== false){ 
                return $ret; 
            } 
            else{ 
                $ret['props'][] = $line; 
            } 
        } 
        return $ret; 
    } 
 
    /** 
     * Create standard CSS file from processed tree 
     * 
     * @param (array) file: Tree parsed from contents 
     * @param (string) tag: Current tag depth 
     */  
    function processFile($file, $tag=''){ 
        // Only add props if it exists with a tag 
        if (($tag = trim($tag)) && $tag != '' && $file['props']){ 
            // Remove Lingering direct descendent tag and trim it 
            $trimedTag = trim(preg_replace('/[>]$/', '', $tag)); 
            $str = "$trimedTag {\n\t" . implode("\n\t", $file['props']) . "\n}\n\n"; 
        } 
 
        // Loop through nested levels 
        foreach ($file as $key => $value) 
            if ($key != 'props')  
                $str .= $this->processFile($value, $tag.' '.$key); 
 
        // Return concatenated string 
        return $str; 
    } 
}; 
 
$oocss = new ObjectOrientedCSS; 
?> 
 
 |