View source
<?php
class CSSCompression_Cleanup {
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",
" ",
),
);
public function __construct(CSSCompression_Control $control) {
$this->Control = $control;
$this->token = CSSCompression::TOKEN;
$this->options =& $control->Option->options;
$this->rtoken = "/({$this->token})(.*?)({$this->token})/";
array_push($this->rescape, $this->rtoken);
}
public function cleanup(&$selectors, &$details) {
foreach ($details as $i => &$value) {
if (isset($selectors[$i]) && strpos($selectors[$i], $this->token) === 0) {
continue;
}
if ($this->options['rm-multi-define']) {
$value = $this
->removeMultipleDefinitions($value);
}
$value = $this
->removeUnnecessarySemicolon($value);
}
return array(
$selectors,
$details,
);
}
public function removeInjections($css) {
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;
}
}
$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;
}
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 $val;
}
private function removeUnnecessarySemicolon($value) {
return preg_replace($this->rsemi, '', $value);
}
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);
}
}
}