I have a bunch of CSS files that get loaded on every page (header, global, main page, footer, etc.).
I have written a simple PHP script that compiles them into a single string and then outputs that string.
<?php
set_include_path('../');
header('Content-Type: text/css');
$q = $_GET['q'];
$patterns = array(
'/.*[\.]{2,}.*/',
'/,\//',
'/^\//'
);
$replacements = array(
'',
',',
''
);
$q = preg_replace($patterns, $replacements, $q);
$css = explode(",", $q);
$output = '';
foreach( $css as $link )
{
$output .= include($link);
}
print $output;
?>
it can be called (and the way I am calling it) like this:
<?php
$cssLinks = array(
"/global/global.css",
"/styles/local.css",
$tmpl->headerContent['css']['link'],
$tmpl->appContent['css']['link'],
"/styles/css3buttons.css"
);
$css = implode(",", $cssLinks);
?>
<link rel="stylesheet" href="/components/CSS.php?q=<?= $css; ?>" type="text/css" />
Which results in a string like this:
<link rel="stylesheet" href="/components/CSS.php?q=/global/global.css,/styles/local.css,/styles/header.css,/styles/index.css,/styles/css3buttons.css" type="text/css" />
This is fine, and – more importantly – it works.
What is my question, then, you ask?
It’s a two-parter:
- What security vulnerabilities am I overlooking in the script?
- I’ve removed any directory traversal possibilities, but what else?
- I do need to be able to change what the links are, so I can’t hard-code them into this script. For example,
$tmpl->appContent['css']['link']is a dynamic stylesheet for each page, of which there will be many.
- How can I add line breaks between the included files?
- I’ve added
$output .= '\n\n';in theforeach()loop, but it doesn’t work. - I’m still stuck with output like:
- I’ve added
#footer, #push {
height: 3em;
padding-top: 1em;
}#header{
The CSS listed works but I would prefer to have the #header block two lines down, like:
#footer, #push {
height: 3em;
padding-top: 1em;
}
#header{
(I apologize about the strange code block, Markdown broke horrendously on those hashes, and I couldn’t figure out how to fix it).
Note, this lack of line breaks only happens at the junction between two different files. The code inside each CSS file is formated just as it should be.
You should prefer to pass only basenames to the CSS.php merge script:
Then it becomes safer to implement in CSS.php with just:
The only difference is that this script now has a little intelligence and knows where to look for the stylesheets. So you don’t lose the flexibility of having variable stylesheet parts glued together.