1<?php 2 3/* 4 * This file is part of the Assetic package, an OpenSky project. 5 * 6 * (c) 2010-2014 OpenSky Project Inc 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Assetic\Util; 13 14/** 15 * CSS Utils. 16 * 17 * @author Kris Wallsmith <kris.wallsmith@gmail.com> 18 */ 19abstract class CssUtils 20{ 21 const REGEX_URLS = '/url\((["\']?)(?P<url>.*?)(\\1)\)/'; 22 const REGEX_IMPORTS = '/@import (?:url\()?(\'|"|)(?P<url>[^\'"\)\n\r]*)\1\)?;?/'; 23 const REGEX_IMPORTS_NO_URLS = '/@import (?!url\()(\'|"|)(?P<url>[^\'"\)\n\r]*)\1;?/'; 24 const REGEX_IE_FILTERS = '/src=(["\']?)(?P<url>.*?)\\1/'; 25 const REGEX_COMMENTS = '/(\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)/'; 26 27 /** 28 * Filters all references -- url() and "@import" -- through a callable. 29 * 30 * @param string $content The CSS 31 * @param callable $callback A PHP callable 32 * 33 * @return string The filtered CSS 34 */ 35 public static function filterReferences($content, $callback) 36 { 37 $content = static::filterUrls($content, $callback); 38 $content = static::filterImports($content, $callback, false); 39 $content = static::filterIEFilters($content, $callback); 40 41 return $content; 42 } 43 44 /** 45 * Filters all CSS url()'s through a callable. 46 * 47 * @param string $content The CSS 48 * @param callable $callback A PHP callable 49 * 50 * @return string The filtered CSS 51 */ 52 public static function filterUrls($content, $callback) 53 { 54 $pattern = static::REGEX_URLS; 55 56 return static::filterCommentless($content, function ($part) use (& $callback, $pattern) { 57 return preg_replace_callback($pattern, $callback, $part); 58 }); 59 } 60 61 /** 62 * Filters all CSS imports through a callable. 63 * 64 * @param string $content The CSS 65 * @param callable $callback A PHP callable 66 * @param Boolean $includeUrl Whether to include url() in the pattern 67 * 68 * @return string The filtered CSS 69 */ 70 public static function filterImports($content, $callback, $includeUrl = true) 71 { 72 $pattern = $includeUrl ? static::REGEX_IMPORTS : static::REGEX_IMPORTS_NO_URLS; 73 74 return static::filterCommentless($content, function ($part) use (& $callback, $pattern) { 75 return preg_replace_callback($pattern, $callback, $part); 76 }); 77 } 78 79 /** 80 * Filters all IE filters (AlphaImageLoader filter) through a callable. 81 * 82 * @param string $content The CSS 83 * @param callable $callback A PHP callable 84 * 85 * @return string The filtered CSS 86 */ 87 public static function filterIEFilters($content, $callback) 88 { 89 $pattern = static::REGEX_IE_FILTERS; 90 91 return static::filterCommentless($content, function ($part) use (& $callback, $pattern) { 92 return preg_replace_callback($pattern, $callback, $part); 93 }); 94 } 95 96 /** 97 * Filters each non-comment part through a callable. 98 * 99 * @param string $content The CSS 100 * @param callable $callback A PHP callable 101 * 102 * @return string The filtered CSS 103 */ 104 public static function filterCommentless($content, $callback) 105 { 106 $result = ''; 107 foreach (preg_split(static::REGEX_COMMENTS, $content, -1, PREG_SPLIT_DELIM_CAPTURE) as $part) { 108 if (!preg_match(static::REGEX_COMMENTS, $part, $match) || $part != $match[0]) { 109 $part = call_user_func($callback, $part); 110 } 111 112 $result .= $part; 113 } 114 115 return $result; 116 } 117 118 /** 119 * Extracts all references from the supplied CSS content. 120 * 121 * @param string $content The CSS content 122 * 123 * @return array An array of unique URLs 124 */ 125 public static function extractImports($content) 126 { 127 $imports = array(); 128 static::filterImports($content, function ($matches) use (&$imports) { 129 $imports[] = $matches['url']; 130 }); 131 132 return array_unique(array_filter($imports)); 133 } 134 135 final private function __construct() 136 { 137 } 138} 139