Parse a CSS file with PHP

2019-01-05 05:43发布

I want to parse (in a special way) a CSS file with PHP.

Example:

cssfile.css:

#stuff {
    background-color: red;
}

#content.postclass-subcontent {
    background-color: red;
}

#content2.postclass-subcontent2 {
    background-color: red;
}

And I want that PHP returns me each class name that have the postclass in its name.

The result look like an array having in this example:

arrayentry1:
#content.postclass-subcontent
arrayentry2:
#content2.postclass-subcontent2

But I'm worse at regular expressions. somehow search for "postclass" and then grap the hole line and put into an array.


thank you and i used it to parse a css file simliar to a confic file.

$(function () {
    $.get('main.css', function (data) {
        data = data.match(/(#[a-z0-9]*?\ .?postclass.*?)\s?\{/g);
        if (data) {
            $.each(data, function (index, value) {
                value = value.substring(0, value.length - 2);
                $(value.split(' .')[0]).wrapInner('<div class="' + value.split('.')[1] + '" />');
            });
        }
    });
});

was my final code. so i can wrap easily a div around some hardcode-html without editing the layout. so i just have to edit my cssfile and add there something like

id .postclass-class { some styles }

and my code searchs for the id and wraps the inner content with an div. i needed that for quickfixes when i just have to add a div around something for a clear or a background.

6条回答
▲ chillily
2楼-- · 2019-01-05 06:07

There is a very good CSS parser class in PHP. Use it. Here is its sample code:

<?php
include("cssparser.php");

$css = new cssparser();
$css->ParseStr("b {font-weight: bold; color: #777777;} b.test{text-decoration: underline;}");
echo $css->Get("b","color");     // returns #777777
echo $css->Get("b.test","color");// returns #777777
echo $css->Get(".test","color"); // returns an empty string
?> 
查看更多
萌系小妹纸
3楼-- · 2019-01-05 06:13

Here is a quick and dirty standalone hack using regex:

$input = '
#stuff {
    background-color: red;
}

#content.postclass-subcontent {
    background-color: red;
}

#content2.postclass-subcontent2 {
    background-color: red;
}
';

$cssClassName = 'postclass';
preg_match_all('/(#[a-z0-9]*?\.?'.addcslashes($cssClassName, '-').'.*?)\s?\{/', $input, $matches);
var_dump($matches[1]);

Results in:

array(2) {
  [0]=>
  string(29) "#content.postclass-subcontent"
  [1]=>
  string(31) "#content2.postclass-subcontent2"
}
查看更多
劳资没心,怎么记你
4楼-- · 2019-01-05 06:21

I found a solution:

function parse($file){
    $css = file_get_contents($file);
    preg_match_all( '/(?ims)([a-z0-9\s\.\:#_\-@,]+)\{([^\}]*)\}/', $css, $arr);
    $result = array();
    foreach ($arr[0] as $i => $x){
        $selector = trim($arr[1][$i]);
        $rules = explode(';', trim($arr[2][$i]));
        $rules_arr = array();
        foreach ($rules as $strRule){
            if (!empty($strRule)){
                $rule = explode(":", $strRule);
                $rules_arr[trim($rule[0])] = trim($rule[1]);
            }
        }

        $selectors = explode(',', trim($selector));
        foreach ($selectors as $strSel){
            $result[$strSel] = $rules_arr;
        }
    }
    return $result;
}
$css = parse('css/'.$user['blog'].'.php');

use:

$css['#selector']['color'];
查看更多
孤傲高冷的网名
5楼-- · 2019-01-05 06:21
<?php

$css = <<<CSS
#selector { display:block; width:100px; }
#selector a { float:left; text-decoration:none }
CSS;

//
function BreakCSS($css)
{

    $results = array();

    preg_match_all('/(.+?)\s?\{\s?(.+?)\s?\}/', $css, $matches);
    foreach($matches[0] AS $i=>$original)
        foreach(explode(';', $matches[2][$i]) AS $attr)
                if (strlen($attr) > 0) // for missing semicolon on last element, which is legal
                {
                        // Explode on the CSS attributes defined
                        list($name, $value) = explode(':', $attr);
                        $results[$matches[1][$i]][trim($name)] = trim($value);
                }
    return $results;
}
var_dump(BreakCSS($css));

//see its same

查看更多
We Are One
6楼-- · 2019-01-05 06:24

Just for completeness there is also another library for parsing CSS: sabberworm / PHP-CSS-Parser.

Homepage: http://www.sabberworm.com/blog/2010/6/10/php-css-parser
GitHub: http://github.com/sabberworm/PHP-CSS-Parser
Gist: http://packagist.org/packages/sabberworm/php-css-parser
Last update: May 31, 2017 (Stating this because the date in the blog entry may mislead you that it isn't updated anymore.)

Unfortunately this project is bit too robust. From quite simple CSS creates very chatty structure. Also before first use you have to deal with composer (I myself did end-up adding require_once for each file into parser.php).

查看更多
Melony?
7楼-- · 2019-01-05 06:31

In addition to Gabriel Anderson's answer to handle css @media queries, child selector > ,base64 images, and input[type="button"]:hover

function parse_css_selectors($css,$media_queries=true){

    $result = $media_blocks = [];

    //---------------parse css media queries------------------

    if($media_queries==true){

        $media_blocks=parse_css_media_queries($css);
    }

    if(!empty($media_blocks)){

        //---------------get css blocks-----------------

        $css_blocks=$css;

        foreach($media_blocks as $media_block){

            $css_blocks=str_ireplace($media_block,'~£&#'.$media_block.'~£&#',$css_blocks);
        }

        $css_blocks=explode('~£&#',$css_blocks);

        //---------------parse css blocks-----------------

        $b=0;

        foreach($css_blocks as $css_block){

            preg_match('/(\@media[^\{]+)\{(.*)\}\s+/ims',$css_block,$block);

            if(isset($block[2])&&!empty($block[2])){

                $result[$block[1]]=parse_css_selectors($block[2],false);
            }
            else{

                $result[$b]=parse_css_selectors($css_block,false);
            }

            ++$b;
        }
    }
    else{

        //---------------escape base64 images------------------

        $css=preg_replace('/(data\:[^;]+);/i','$1~£&#',$css);

        //---------------parse css selectors------------------

        preg_match_all('/([^\{\}]+)\{([^\}]*)\}/ims', $css, $arr);

        foreach ($arr[0] as $i => $x){

            $selector = trim($arr[1][$i]);

            $rules = explode(';', trim($arr[2][$i]));

            $rules_arr = [];

            foreach($rules as $strRule){

                if(!empty($strRule)){

                    $rule = explode(":", $strRule,2);

                    if(isset($rule[1])){

                        $rules_arr[trim($rule[0])] = str_replace('~£&#',';',trim($rule[1]));
                    }
                    else{
                        //debug
                    }
                }
            }

            $selectors = explode(',', trim($selector));

            foreach ($selectors as $strSel){

                if($media_queries===true){

                    $result[$b][$strSel] = $rules_arr;
                }
                else{

                    $result[$strSel] = $rules_arr;
                }
            }
        }
    }
    return $result;
}

function parse_css_media_queries($css){

    $mediaBlocks = array();

    $start = 0;
    while(($start = strpos($css, "@media", $start)) !== false){

        // stack to manage brackets
        $s = array();

        // get the first opening bracket
        $i = strpos($css, "{", $start);

        // if $i is false, then there is probably a css syntax error
        if ($i !== false){

            // push bracket onto stack
            array_push($s, $css[$i]);

            // move past first bracket
            $i++;

            while (!empty($s)){

                // if the character is an opening bracket, push it onto the stack, otherwise pop the stack
                if ($css[$i] == "{"){

                    array_push($s, "{");
                }
                elseif ($css[$i] == "}"){

                    array_pop($s);
                }

                $i++;
            }

            // cut the media block out of the css and store
            $mediaBlocks[] = substr($css, $start, ($i + 1) - $start);

            // set the new $start to the end of the block
            $start = $i;
        }
    }

    return $mediaBlocks;
}

Resources

查看更多
登录 后发表回答