PageRenderTime 60ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/sally/core/lib/Scaffold/libraries/Scaffold/CSS.php

https://bitbucket.org/mediastuttgart/sallycms-0.5
PHP | 371 lines | 194 code | 45 blank | 132 comment | 14 complexity | 12266e3e7ae5536478259624695387dc MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * CSS Utilities
  4. *
  5. * Has methods for interacting with the CSS string
  6. * and makes it very easy to find properties and values within the css
  7. *
  8. * @package CSScaffold
  9. * @author Anthony Short
  10. * @license BSD License
  11. */
  12. class Scaffold_CSS
  13. {
  14. /**
  15. * Server path to this CSS file
  16. *
  17. * @var string
  18. */
  19. public $path;
  20. /**
  21. * The name of this CSS file
  22. *
  23. * @var string
  24. */
  25. public $file;
  26. /**
  27. * The string of CSS code
  28. *
  29. * @var string
  30. */
  31. public $string;
  32. /**
  33. * Constructor
  34. *
  35. * @param $file
  36. * @return void
  37. */
  38. public function __construct($file)
  39. {
  40. $this->path = dirname($file);
  41. $this->file = $file;
  42. $this->string = $this->remove_inline_comments(file_get_contents($file));
  43. }
  44. /**
  45. * Returns the CSS string when treated as a string
  46. *
  47. * @return string
  48. */
  49. public function __toString()
  50. {
  51. return $this->string;
  52. }
  53. /**
  54. * Compresses down the CSS file. Not a complete compression,
  55. * but enough to minimize parsing time.
  56. *
  57. * @return string $css
  58. */
  59. public function compress($css)
  60. {
  61. # Remove comments
  62. $this->string = $this->remove_comments($this->string);
  63. # Remove extra white space
  64. $this->string = preg_replace('/\s+/', ' ', $css);
  65. # Remove line breaks
  66. $this->string = preg_replace('/\n|\r/', '', $css);
  67. }
  68. /**
  69. * Removes inline comments
  70. *
  71. * @return return type
  72. */
  73. public function remove_inline_comments($css)
  74. {
  75. return preg_replace('#(\s|$)//.*$#Umsi', '', $css);
  76. }
  77. /**
  78. * Removes css comments
  79. *
  80. * @return string $css
  81. */
  82. public function remove_comments($css)
  83. {
  84. $css = $this->convert_entities('encode', $css);
  85. $css = trim(preg_replace('#/\*[^*]*\*+([^/*][^*]*\*+)*/#', '', $css));
  86. $css = $this->convert_entities('decode', $css);
  87. $css = $this->remove_inline_comments($css);
  88. return $css;
  89. }
  90. /**
  91. * Finds CSS 'functions'. These are things like url(), embed() etc.
  92. *
  93. * @author Anthony Short
  94. * @param $name
  95. * @param $capture_group
  96. * @return array
  97. */
  98. public function find_functions($name, $capture_group = "")
  99. {
  100. $regex =
  101. "/
  102. {$name}
  103. (
  104. \s*\(\s*
  105. ( (?: (?1) | [^()]+ )* )
  106. \s*\)\s*
  107. )
  108. /sx";
  109. if(preg_match_all($regex, $this->string, $match))
  110. {
  111. return ($capture_group == "") ? $match : $match[$capture_group];
  112. }
  113. else
  114. {
  115. return array();
  116. }
  117. }
  118. /**
  119. * Finds @groups within the css and returns
  120. * an array with the values, and groups.
  121. *
  122. * @author Anthony Short
  123. * @param $group string
  124. * @param $css string
  125. */
  126. public function find_at_group($group, $remove = true)
  127. {
  128. $found = array();
  129. $regex =
  130. "/
  131. # Group name
  132. @{$group}
  133. # Flag
  134. (?:
  135. \(( [^)]*? )\)
  136. )?
  137. [^{]*?
  138. (
  139. ([0-9a-zA-Z\_\-\@*&]*?)\s*
  140. \{
  141. ( (?: [^{}]+ | (?2) )*)
  142. \}
  143. )
  144. /ixs";
  145. if(preg_match_all($regex, $this->string, $matches))
  146. {
  147. $found['groups'] = $matches[0];
  148. $found['flag'] = $matches[1];
  149. $found['content'] = $matches[4];
  150. foreach($matches[4] as $key => $value)
  151. {
  152. // Remove comments to prevent breaking it
  153. $value = $this->remove_comments($value);
  154. foreach(explode(";", substr($value, 0, -1)) as $value)
  155. {
  156. // Encode any colons inside quotations
  157. if( preg_match_all('/[\'"](.*?\:.*?)[\'"]/',$value,$m) )
  158. {
  159. $value = str_replace($m[0][0],str_replace(':','#COLON#',$m[0][0]),$value);
  160. }
  161. $value = explode(":", $value);
  162. // Make sure it's set
  163. if(isset($value[1]))
  164. {
  165. $found['values'][trim($value[0])] = str_replace('#COLON#', ':', Scaffold::unquote($value[1]));
  166. }
  167. }
  168. }
  169. // Remove the found @ groups
  170. if($remove === true)
  171. {
  172. $this->string = str_replace($found['groups'], array(), $this->string);
  173. }
  174. return $found;
  175. }
  176. return false;
  177. }
  178. /**
  179. * Finds selectors which contain a particular property
  180. *
  181. * @author Anthony Short
  182. * @param $css
  183. * @param $property string
  184. * @param $value string
  185. */
  186. public function find_selectors_with_property($property, $value = ".*?")
  187. {
  188. if(preg_match_all("/([^{}]*)\s*\{\s*[^}]*(".$property."\s*\:\s*(".$value.")\s*\;).*?\s*\}/sx", $this->string, $match))
  189. {
  190. return $match;
  191. }
  192. else
  193. {
  194. return array();
  195. }
  196. }
  197. /**
  198. * Finds all properties with a particular value
  199. *
  200. * @author Anthony Short
  201. * @param $property
  202. * @param $value
  203. * @param $css
  204. * @return array
  205. */
  206. public function find_properties_with_value($property, $value = ".*?")
  207. {
  208. # Make the property name regex-friendly
  209. $property = Scaffold_Utils::preg_quote($property);
  210. $regex = "/ ({$property}) \s*\:\s* ({$value}) /sx";
  211. if(preg_match_all($regex, $this->string, $match))
  212. {
  213. return $match;
  214. }
  215. else
  216. {
  217. return array();
  218. }
  219. }
  220. /**
  221. * Finds a selector and returns it as string
  222. *
  223. * @author Anthony Short
  224. * @param $selector string
  225. * @param $css string
  226. */
  227. public function find_selectors($selector, $recursive = "")
  228. {
  229. if($recursive != "")
  230. {
  231. $recursive = "|(?{$recursive})";
  232. }
  233. $regex =
  234. "/
  235. # This is the selector we're looking for
  236. ({$selector})
  237. # Return all inner selectors and properties
  238. (
  239. ([0-9a-zA-Z\_\-\*&]*?)\s*
  240. \{
  241. (?P<properties>(?:[^{}]+{$recursive})*)
  242. \}
  243. )
  244. /xs";
  245. if(preg_match_all($regex, $this->string, $match))
  246. {
  247. return $match;
  248. }
  249. else
  250. {
  251. return array();
  252. }
  253. }
  254. /**
  255. * Finds all properties within a css string
  256. *
  257. * @author Anthony Short
  258. * @param $property string
  259. * @param $css string
  260. */
  261. public function find_property($property)
  262. {
  263. if(preg_match_all('/('.Scaffold_Utils::preg_quote($property).')\s*\:\s*(.*?)\s*\;/sx', $this->string, $matches))
  264. {
  265. return (array)$matches;
  266. }
  267. else
  268. {
  269. return array();
  270. }
  271. }
  272. /**
  273. * Check if a selector exists
  274. *
  275. * @param $name
  276. * @return boolean
  277. */
  278. public function selector_exists($name)
  279. {
  280. return preg_match('/'.preg_quote($name).'\s*?({|,)/', $this->string);
  281. }
  282. /**
  283. * Removes all instances of a particular property from the css string
  284. *
  285. * @author Anthony Short
  286. * @param $property string
  287. * @param $value string
  288. * @param $css string
  289. */
  290. public function remove_properties($property, $value)
  291. {
  292. return preg_replace('/'.$property.'\s*\:\s*'.$value.'\s*\;/', '', $this->string);
  293. }
  294. /**
  295. * Encodes or decodes parts of the css that break the xml
  296. *
  297. * @author Anthony Short
  298. * @param $css
  299. * @return string
  300. */
  301. public function convert_entities($action = 'encode', $css = false)
  302. {
  303. if($css === false)
  304. $css =& $this->string;
  305. $css_replacements = array(
  306. '"' => '#SCAFFOLD-QUOTE#',
  307. '>' => '#SCAFFOLD-GREATER#',
  308. '&' => '#SCAFFOLD-PARENT#',
  309. 'data:image/PNG;' => '#SCAFFOLD-IMGDATA-PNG#',
  310. 'data:image/JPG;' => "#SCAFFOLD-IMGDATA-JPG#",
  311. 'data:image/png;' => '#SCAFFOLD-IMGDATA-PNG#',
  312. 'data:image/jpg;' => "#SCAFFOLD-IMGDATA-JPG#",
  313. 'http://' => "#SCAFFOLD-HTTP#",
  314. );
  315. switch ($action)
  316. {
  317. case 'decode':
  318. $this->string = str_replace(array_values($css_replacements),array_keys($css_replacements), $this->string);
  319. break;
  320. case 'encode':
  321. $this->string = str_replace(array_keys($css_replacements),array_values($css_replacements), $this->string);
  322. break;
  323. }
  324. return $css;
  325. }
  326. }