File

advagg_css_compress/css-compressor-3.x/src/lib/Cleanup.inc

View source
<?php


/**
 * CSS Compressor [VERSION]
 * [DATE]
 * Corey Hart @ http://www.codenothing.com
 */
class CSSCompression_Cleanup {
    
    /**
     * Cleanup patterns
     *
     * @class Control: Compression Controller
     * @param (string) token: Copy of the injection token
     * @param (regex) rtoken: Token regex built upon instantiation
     * @param (array) options: Reference to options
     * @param (regex) rsemi: Checks for last semit colon in details
     * @param (regex) rsemicolon: Checks for semicolon without an escape '\' character before it
     * @param (regex) rspace: Checks for space without an escape '\' character before it
     * @param (regex) rcolon: Checks for colon without an escape '\' character before it
     * @param (regex) rquote: Checks for quote (') without an escape '\' character before it
     * @param (array) rescape: Array of patterns for groupings that should be escaped
     * @param (array) escaped: Contains patterns and replacements for espaced characters
     */
    private $Control;
    private $token = '';
    private $rtoken = '';
    private $options = array();
    private $rsemi = "/;\$/";
    private $rsemicolon = "/(?<!\\\\);/";
    private $rspace = "/(?<!\\\\)\\s/";
    private $rcolon = "/(?<!\\\\):/";
    private $rquote = "/(?<!\\\\)'/";
    private $rescape = array(
        "/((?<!\\\\)\")(.*?)((?<!\\\\)\")/",
        "/((?<!\\\\)')(.*?)((?<!\\\\)')/",
        "/(url\\()(.*?)(\\))/",
    );
    private $escaped = array(
        'search' => array(
            "\\:",
            "\\;",
            "\\}",
            "\\{",
            "\\@",
            "\\!",
            "\\,",
            "\\>",
            "\\+",
            "\\~",
            "\\/",
            "\\*",
            "\\.",
            "\\=",
            "\\#",
            "\\r",
            "\\n",
            "\\t",
            "\\ ",
        ),
        'replace' => array(
            ":",
            ";",
            "}",
            "{",
            "@",
            "!",
            ",",
            ">",
            "+",
            "~",
            "/",
            "*",
            ".",
            "=",
            "#",
            "\r",
            "\n",
            "\t",
            " ",
        ),
    );
    
    /**
     * Build the token regex based on defined token
     *
     * @param (class) control: CSSCompression Controller
     */
    public function __construct(CSSCompression_Control $control) {
        $this->Control = $control;
        $this->token = CSSCompression::TOKEN;
        $this->options =& $control->Option->options;
        // Have to build the token regexs after initialization
        $this->rtoken = "/({$this->token})(.*?)({$this->token})/";
        array_push($this->rescape, $this->rtoken);
    }
    
    /**
     * Central cleanup process, removes all injections
     *
     * @param (array) selectors: Array of selectors
     * @param (array) details: Array of details
     */
    public function cleanup(&$selectors, &$details) {
        foreach ($details as $i => &$value) {
            // Auto skip sections
            if (isset($selectors[$i]) && strpos($selectors[$i], $this->token) === 0) {
                continue;
            }
            // Removing dupes
            if ($this->options['rm-multi-define']) {
                $value = $this->removeMultipleDefinitions($value);
            }
            $value = $this->removeUnnecessarySemicolon($value);
        }
        return array(
            $selectors,
            $details,
        );
    }
    
    /**
     * Removes '\' from possible splitter characters in URLs
     *
     * @param (string) css: Full css sheet
     */
    public function removeInjections($css) {
        // Remove escaped characters
        foreach ($this->rescape as $regex) {
            $pos = 0;
            while (preg_match($regex, $css, $match, PREG_OFFSET_CAPTURE, $pos)) {
                $value = $match[1][0] . str_replace($this->escaped['search'], $this->escaped['replace'], $match[2][0]) . $match[3][0];
                $css = substr_replace($css, $value, $match[0][1], strlen($match[0][0]));
                $pos = $match[0][1] + strlen($value) + 1;
            }
        }
        // Remove token injections
        $pos = 0;
        while (preg_match($this->rtoken, $css, $match, PREG_OFFSET_CAPTURE, $pos)) {
            $value = $match[2][0];
            $id = substr($css, $match[0][1] - 4, 4) == '[id=' ? true : false;
            $class = substr($css, $match[0][1] - 7, 7) == '[class=' ? true : false;
            if (preg_match($this->rspace, $value) || !$id && !$class) {
                $quote = preg_match($this->rquote, $value) ? "\"" : "'";
                $value = "{$quote}{$value}{$quote}";
                $css = substr_replace($css, $value, $match[0][1], strlen($match[0][0]));
                $pos = $match[0][1] + strlen($value) + 1;
            }
            else {
                $css = substr_replace($css, $value, $match[0][1], strlen($match[0][0]));
                $pos = $match[0][1] + strlen($value) + 1;
            }
        }
        return $css;
    }
    
    /**
     * Removes multiple definitions that were created during compression
     *
     * @param (string) val: CSS Selector Properties
     */
    private function removeMultipleDefinitions($val = '') {
        $storage = array();
        $arr = preg_split($this->rsemicolon, $val);
        foreach ($arr as $x) {
            if ($x) {
                list($a, $b) = preg_split($this->rcolon, $x, 2);
                $storage[$a] = $b;
            }
        }
        if ($storage) {
            $val = '';
            foreach ($storage as $x => $y) {
                $val .= "{$x}:{$y};";
            }
        }
        // Return converted val
        return $val;
    }
    
    /**
     * Removes last semicolons on the final property of a set
     *
     * @param (string) value: rule set
     */
    private function removeUnnecessarySemicolon($value) {
        return preg_replace($this->rsemi, '', $value);
    }
    
    /**
     * Access to private methods for testing
     *
     * @param (string) method: Method to be called
     * @param (array) args: Array of paramters to be passed in
     */
    public function access($method, $args) {
        if (method_exists($this, $method)) {
            if ($method == 'cleanup') {
                return $this->cleanup($args[0], $args[1]);
            }
            else {
                return call_user_func_array(array(
                    $this,
                    $method,
                ), $args);
            }
        }
        else {
            throw new CSSCompression_Exception("Unknown method in Cleanup Class - " . $method);
        }
    }

}

Classes

Title Deprecated Summary
CSSCompression_Cleanup CSS Compressor [VERSION] [DATE] Corey Hart @ http://www.codenothing.com