4 [![build status](https://api.travis-ci.org/sabberworm/PHP-CSS-Parser.svg)](https://travis-ci.org/sabberworm/PHP-CSS-Parser) [![HHVM Status](http://hhvm.h4cc.de/badge/sabberworm/php-css-parser.svg)](http://hhvm.h4cc.de/package/sabberworm/php-css-parser)
6 A Parser for CSS Files written in PHP. Allows extraction of CSS files into a data structure, manipulation of said structure and output as (optimized) CSS.
10 ### Installation using composer
12 Add php-css-parser to your composer.json
17 "sabberworm/php-css-parser": "*"
24 To use the CSS Parser, create a new instance. The constructor takes the following form:
27 new Sabberworm\CSS\Parser($sText);
30 To read a file, for example, you’d do the following:
33 $oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'));
34 $oCssDocument = $oCssParser->parse();
37 The resulting CSS document structure can be manipulated prior to being output.
43 The charset option is used only if no @charset declaration is found in the CSS file. UTF-8 is the default, so you won’t have to create a settings object at all if you don’t intend to change that.
46 $oSettings = Sabberworm\CSS\Settings::create()->withDefaultCharset('windows-1252');
47 new Sabberworm\CSS\Parser($sText, $oSettings);
52 To have the parser choke on invalid rules, supply a thusly configured Sabberworm\CSS\Settings object:
55 $oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'), Sabberworm\CSS\Settings::create()->beStrict());
58 #### Disable multibyte functions
60 To achieve faster parsing, you can choose to have PHP-CSS-Parser use regular string functions instead of `mb_*` functions. This should work fine in most cases, even for UTF-8 files, as all the multibyte characters are in string literals. Still it’s not recommended to use this with input you have no control over as it’s not thoroughly covered by test cases.
63 $oSettings = Sabberworm\CSS\Settings::create()->withMultibyteSupport(false);
64 new Sabberworm\CSS\Parser($sText, $oSettings);
69 The resulting data structure consists mainly of five basic types: `CSSList`, `RuleSet`, `Rule`, `Selector` and `Value`. There are two additional types used: `Import` and `Charset` which you won’t use often.
73 `CSSList` represents a generic CSS container, most likely containing declaration blocks (rule sets with a selector) but it may also contain at-rules, charset declarations, etc. `CSSList` has the following concrete subtypes:
75 * `Document` – representing the root of a CSS file.
76 * `MediaQuery` – represents a subsection of a CSSList that only applies to a output device matching the contained media query.
78 To access the items stored in a `CSSList` – like the document you got back when calling `$oCssParser->parse()` –, use `getContents()`, then iterate over that collection and use instanceof to check whether you’re dealing with another `CSSList`, a `RuleSet`, a `Import` or a `Charset`.
80 To append a new item (selector, media query, etc.) to an existing `CSSList`, construct it using the constructor for this class and use the `append($oItem)` method.
84 `RuleSet` is a container for individual rules. The most common form of a rule set is one constrained by a selector. The following concrete subtypes exist:
86 * `AtRuleSet` – for generic at-rules which do not match the ones specifically mentioned like @import, @charset or @media. A common example for this is @font-face.
87 * `DeclarationBlock` – a RuleSet constrained by a `Selector`; contains an array of selector objects (comma-separated in the CSS) as well as the rules to be applied to the matching elements.
89 Note: A `CSSList` can contain other `CSSList`s (and `Import`s as well as a `Charset`) while a `RuleSet` can only contain `Rule`s.
91 If you want to manipulate a `RuleSet`, use the methods `addRule(Rule $oRule)`, `getRules()` and `removeRule($mRule)` (which accepts either a Rule instance or a rule name; optionally suffixed by a dash to remove all related rules).
95 `Rule`s just have a key (the rule) and a value. These values are all instances of a `Value`.
99 `Value` is an abstract class that only defines the `render` method. The concrete subclasses for atomic value types are:
101 * `Size` – consists of a numeric `size` value and a unit.
102 * `Color` – colors can be input in the form #rrggbb, #rgb or schema(val1, val2, …) but are always stored as an array of ('s' => val1, 'c' => val2, 'h' => val3, …) and output in the second form.
103 * `CSSString` – this is just a wrapper for quoted strings to distinguish them from keywords; always output with double quotes.
104 * `URL` – URLs in CSS; always output in URL("") notation.
106 There is another abstract subclass of `Value`, `ValueList`. A `ValueList` represents a lists of `Value`s, separated by some separation character (mostly `,`, whitespace, or `/`). There are two types of `ValueList`s:
108 * `RuleValueList` – The default type, used to represent all multi-valued rules like `font: bold 12px/3 Helvetica, Verdana, sans-serif;` (where the value would be a whitespace-separated list of the primitive value `bold`, a slash-separated list and a comma-separated list).
109 * `CSSFunction` – A special kind of value that also contains a function name and where the values are the function’s arguments. Also handles equals-sign-separated argument lists like `filter: alpha(opacity=90);`.
111 #### Convenience methods
113 There are a few convenience methods on Document to ease finding, manipulating and deleting rules:
115 * `getAllDeclarationBlocks()` – does what it says; no matter how deeply nested your selectors are. Aliased as `getAllSelectors()`.
116 * `getAllRuleSets()` – does what it says; no matter how deeply nested your rule sets are.
117 * `getAllValues()` – finds all `Value` objects inside `Rule`s.
121 * More convenience methods [like `selectorsWithElement($sId/Class/TagName)`, `attributesOfType($sType)`, `removeAttributesOfType($sType)`]
122 * Real multibyte support. Currently only multibyte charsets whose first 255 code points take up only one byte and are identical with ASCII are supported (yes, UTF-8 fits this description).
123 * Named color support (using `Color` instead of an anonymous string literal)
127 ### Use `Parser` to prepend an id to all selectors
131 $oParser = new Sabberworm\CSS\Parser($sText);
132 $oCss = $oParser->parse();
133 foreach($oCss->getAllDeclarationBlocks() as $oBlock) {
134 foreach($oBlock->getSelectors() as $oSelector) {
135 //Loop over all selector parts (the comma-separated strings in a selector) and prepend the id
136 $oSelector->setSelector($sMyId.' '.$oSelector->getSelector());
141 ### Shrink all absolute sizes to half
144 $oParser = new Sabberworm\CSS\Parser($sText);
145 $oCss = $oParser->parse();
146 foreach($oCss->getAllValues() as $mValue) {
147 if($mValue instanceof CSSSize && !$mValue->isRelative()) {
148 $mValue->setSize($mValue->getSize()/2);
153 ### Remove unwanted rules
156 $oParser = new Sabberworm\CSS\Parser($sText);
157 $oCss = $oParser->parse();
158 foreach($oCss->getAllRuleSets() as $oRuleSet) {
159 $oRuleSet->removeRule('font-'); //Note that the added dash will make this remove all rules starting with font- (like font-size, font-weight, etc.) as well as a potential font-rule
160 $oRuleSet->removeRule('cursor');
166 To output the entire CSS document into a variable, just use `->render()`:
169 $oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'));
170 $oCssDocument = $oCssParser->parse();
171 print $oCssDocument->render();
174 If you want to format the output, pass an instance of type `Sabberworm\CSS\OutputFormat`:
177 $oFormat = Sabberworm\CSS\OutputFormat::create()->indentWithSpaces(4)->setSpaceBetweenRules("\n");
178 print $oCssDocument->render($oFormat);
181 Or use one of the predefined formats:
184 print $oCssDocument->render(Sabberworm\CSS\OutputFormat::createPretty());
185 print $oCssDocument->render(Sabberworm\CSS\OutputFormat::createCompact());
188 To see what you can do with output formatting, look at the tests in `tests/Sabberworm/CSS/OutputFormatTest.php`.
192 ### Example 1 (At-Rules)
200 font-family: "CrassRoots";
201 src: url("../media/cr.ttf")
215 #### Structure (`var_dump()`)
218 class Sabberworm\CSS\CSSList\Document#4 (2) {
219 protected $aContents =>
222 class Sabberworm\CSS\Property\Charset#6 (2) {
224 class Sabberworm\CSS\Value\CSSString#5 (2) {
227 protected $iLineNo =>
230 protected $iLineNo =>
234 class Sabberworm\CSS\RuleSet\AtRuleSet#7 (4) {
236 string(9) "font-face"
244 class Sabberworm\CSS\Rule\Rule#8 (4) {
246 string(11) "font-family"
248 class Sabberworm\CSS\Value\CSSString#9 (2) {
250 string(10) "CrassRoots"
251 protected $iLineNo =>
254 private $bIsImportant =>
256 protected $iLineNo =>
263 class Sabberworm\CSS\Rule\Rule#10 (4) {
267 class Sabberworm\CSS\Value\URL#11 (2) {
269 class Sabberworm\CSS\Value\CSSString#12 (2) {
271 string(15) "../media/cr.ttf"
272 protected $iLineNo =>
275 protected $iLineNo =>
278 private $bIsImportant =>
280 protected $iLineNo =>
285 protected $iLineNo =>
289 class Sabberworm\CSS\RuleSet\DeclarationBlock#13 (3) {
290 private $aSelectors =>
293 class Sabberworm\CSS\Property\Selector#14 (2) {
294 private $sSelector =>
296 private $iSpecificity =>
300 class Sabberworm\CSS\Property\Selector#15 (2) {
301 private $sSelector =>
303 private $iSpecificity =>
312 class Sabberworm\CSS\Rule\Rule#16 (4) {
314 string(9) "font-size"
316 class Sabberworm\CSS\Value\Size#17 (4) {
321 private $bIsColorComponent =>
323 protected $iLineNo =>
326 private $bIsImportant =>
328 protected $iLineNo =>
333 protected $iLineNo =>
337 class Sabberworm\CSS\CSSList\KeyFrame#18 (4) {
338 private $vendorKeyFrame =>
339 string(9) "keyframes"
340 private $animationName =>
342 protected $aContents =>
345 class Sabberworm\CSS\RuleSet\DeclarationBlock#19 (3) {
346 private $aSelectors =>
349 class Sabberworm\CSS\Property\Selector#20 (2) {
350 private $sSelector =>
352 private $iSpecificity =>
361 class Sabberworm\CSS\Rule\Rule#21 (4) {
365 class Sabberworm\CSS\Value\Size#22 (4) {
370 private $bIsColorComponent =>
372 protected $iLineNo =>
375 private $bIsImportant =>
377 protected $iLineNo =>
382 protected $iLineNo =>
386 class Sabberworm\CSS\RuleSet\DeclarationBlock#23 (3) {
387 private $aSelectors =>
390 class Sabberworm\CSS\Property\Selector#24 (2) {
391 private $sSelector =>
393 private $iSpecificity =>
402 class Sabberworm\CSS\Rule\Rule#25 (4) {
406 class Sabberworm\CSS\Value\Size#26 (4) {
411 private $bIsColorComponent =>
413 protected $iLineNo =>
416 private $bIsImportant =>
418 protected $iLineNo =>
423 protected $iLineNo =>
427 protected $iLineNo =>
431 protected $iLineNo =>
437 #### Output (`render()`)
441 @font-face {font-family: "CrassRoots";src: url("../media/cr.ttf");}
442 html, body {font-size: 1.6em;}
443 @keyframes mymove {from {top: 0px;}
447 ### Example 2 (Values)
453 margin: 10px 2em 1cm 2%;
454 font-family: Verdana, Helvetica, "Gill Sans", sans-serif;
455 color: red !important;
460 #### Structure (`var_dump()`)
463 class Sabberworm\CSS\CSSList\Document#4 (2) {
464 protected $aContents =>
467 class Sabberworm\CSS\RuleSet\DeclarationBlock#5 (3) {
468 private $aSelectors =>
471 class Sabberworm\CSS\Property\Selector#6 (2) {
472 private $sSelector =>
474 private $iSpecificity =>
483 class Sabberworm\CSS\Rule\Rule#7 (4) {
487 class Sabberworm\CSS\Value\RuleValueList#12 (3) {
488 protected $aComponents =>
491 class Sabberworm\CSS\Value\Size#8 (4) {
496 private $bIsColorComponent =>
498 protected $iLineNo =>
502 class Sabberworm\CSS\Value\Size#9 (4) {
507 private $bIsColorComponent =>
509 protected $iLineNo =>
513 class Sabberworm\CSS\Value\Size#10 (4) {
518 private $bIsColorComponent =>
520 protected $iLineNo =>
524 class Sabberworm\CSS\Value\Size#11 (4) {
529 private $bIsColorComponent =>
531 protected $iLineNo =>
535 protected $sSeparator =>
537 protected $iLineNo =>
540 private $bIsImportant =>
542 protected $iLineNo =>
549 class Sabberworm\CSS\Rule\Rule#13 (4) {
551 string(11) "font-family"
553 class Sabberworm\CSS\Value\RuleValueList#15 (3) {
554 protected $aComponents =>
559 string(9) "Helvetica"
561 class Sabberworm\CSS\Value\CSSString#14 (2) {
563 string(9) "Gill Sans"
564 protected $iLineNo =>
568 string(10) "sans-serif"
570 protected $sSeparator =>
572 protected $iLineNo =>
575 private $bIsImportant =>
577 protected $iLineNo =>
584 class Sabberworm\CSS\Rule\Rule#16 (4) {
589 private $bIsImportant =>
591 protected $iLineNo =>
596 protected $iLineNo =>
600 protected $iLineNo =>
606 #### Output (`render()`)
609 #header {margin: 10px 2em 1cm 2%;font-family: Verdana,Helvetica,"Gill Sans",sans-serif;color: red !important;}
612 ## Contributors/Thanks to
614 * [FMCorz](https://github.com/FMCorz) for many patches and suggestions, for being able to parse comments and IE hacks (in lenient mode).
615 * [Lullabot](https://github.com/Lullabot) for a patch that allows to know the line number for each parsed token.
616 * [ju1ius](https://github.com/ju1ius) for the specificity parsing code and the ability to expand/compact shorthand properties.
617 * [ossinkine](https://github.com/ossinkine) for a 150 time performance boost.
618 * [GaryJones](https://github.com/GaryJones) for lots of input and [http://css-specificity.info/](http://css-specificity.info/).
619 * [docteurklein](https://github.com/docteurklein) for output formatting and `CSSList->remove()` inspiration.
620 * [nicolopignatelli](https://github.com/nicolopignatelli) for PSR-0 compatibility.
621 * [diegoembarcadero](https://github.com/diegoembarcadero) for keyframe at-rule parsing.
622 * [goetas](https://github.com/goetas) for @namespace at-rule support.
623 * [View full list](https://github.com/sabberworm/PHP-CSS-Parser/contributors)
627 * Legacy Support: The latest pre-PSR-0 version of this project can be checked with the `0.9.0` tag.
628 * Running Tests: To run all unit tests for this project, have `phpunit` installed and run `phpunit .`.
632 PHP-CSS-Parser is freely distributable under the terms of an MIT-style license.
634 Copyright (c) 2011 Raphael Schweikert, http://sabberworm.com/
636 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
638 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
640 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.