Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Main filename as seen from inside linked CSS file 3

Status
Not open for further replies.

OsakaWebbie

Programmer
Feb 11, 2003
628
JP
I'm using PHP to construct my CSS output, like this:
HTML:
<link rel="stylesheet" type="text/css" href="style.php" />
Multiple files have the above line in them, and I want to serve up some specific content based on which file is calling it.

My thought was to have a switch statement with cases of the different filenames that need specific content, and I figured there was an environment variable that would contain the name (or path - I don't care) of the file that is linking the CSS (e.g. "search.php" or "list.php"). I checked a few, using a trick like this:
CSS:
#diag:after { content:"<?=$_SERVER['REQUEST_URI']?>"; }
But the few I tried all contained "style.php" itself, not the parent. I couldn't seem to use print_r($_SERVER) in that spot to get the whole array at once, so I'm shooting in the dark. Does anyone know how I can have visibility of the 'parent' filename?
 
Hi

OsakaWebbie said:
I couldn't seem to use print_r($_SERVER) in that spot to get the whole array at once, so I'm shooting in the dark.
Huh ? Just call [tt]print_r()[/tt] inside a CSS commented place :
Code:
/*
[teal]<?php[/teal] [COLOR=darkgoldenrod]print_r[/color][teal]([/teal][navy]$_SERVER[/navy][teal]);[/teal] [teal]?>[/teal]
*/

Sadly, if you go that way, your best option is [tt]$_SERVER['REFERER'][/tt], which as we know, is unreliable. Even worse, when I tried something similar years ago, I discovered that for the embedded resources some browsers sent the URL of the page itself, others sent the referring URL.

So the reliable way is to use GET parameter. Of course, not everywhere, just in the documents that need something special.


Feherke.
[link feherke.github.com/][/url]
 
I would tend to agree with feherke.

Use query string parameters to specify what page you want.

Code:
<link rel="stylesheet" type="text/css" href="style.php[red][b]?parent=search[/b][/red]" />

As for the print_r not sure what you did, it should work directly.

Code:
print_r($_SERVER);

----------------------------------
Phil AKA Vacunita
----------------------------------
Ignorance is not necessarily Bliss, case in point:
Unknown has caused an Unknown Error on Unknown and must be shutdown to prevent damage to Unknown.

Web & Tech
 
Thanks, guys. I know I can pass the page name as a GET parameter (in fact, in a few cases I am already passing other things that way), but this code appears in about 30 files right now, so I thought I'd be clever and avoid editing each one. But I'm aware that that might be the way to go.

In my production version I use a different (perhaps just as unorthodox) technique - in the header setup routine, I get the root part of the filename and make it the id of the <body> tag. Then in the CSS I preface page-specific selectors with "body#search" or whatever. But then all the special CSS for all the pages get sent for every page - yesterday I thought I could reduce the data size by only sending it if it's applicable. I also considered putting the page-specific stuff in each file (that would be easier to manage when I'm making changes to the code, as the relevent CSS would be right there in the same file), but the reason I'm using PHP in the linked CSS is so that I can allow custom colors for different instances (client databases, accessed as subdomains) that use the same basic code, and those color values are not visible to the parent file code. So I should keep everything in style.php if I can.

Help me understand your point about using r_print() without some CSS construct like ":after" to display it on the page - how would I see it? Calling style.php directly as a URL would be missing the point. Called as CSS data in the header of an HTML document, I don't know how I can see all the raw text (normally CSS code, but in this case, extra stuff). Ctrl-U just shows the link, not the contents of the linked file. Firebug shows me the styles as interpreted, not the raw content of the CSS file. How can I see the comments and such? (Even if I give up on my current code kluge idea, this info would be useful for future diagnostics.)
 
Okay, I decided to use the GET parameter - I'm gradually making all the changes now. (I'm using $_SERVER['PHP_SELF'] instead of hardcoding the name, for multiple reasons.) But if you still want to teach me for the future how I can put diagnostic code in something that is handled by the browser as CSS, I'm all ears.
 
This is confusing.

CSS allows the user to cache style information so that the server does not need to waste time/resources generating it and the user does not need to waste bandwidth downloading it with each page load.

If you have different pages that require different tweaks to the main style, you would load additional, static CSS files in the PHP-generated HTML. That is the "cascading" part of CSS.

Custom caching in browsers and proxies will thwart your intent with this PHP CSS. You are likely doing more harm than good with this technique, adding unnecessary bandwidth and time for page loads.
 
Spamjim: The main reason I'm using PHP to build my CSS is because of colors - this application has a single codebase but multiple "clients" with their own database and their own color schemes in some cases. CSS doesn't really have the ability to "cascade" color values as some sort of variables, so I use PHP to do it. Since I'm already doing that, the file cannot be cached anyway, so I might as well only send what is needed for each type of page, rather than everything that might be needed for any page. If I insisted on static CSS files, each client would have to have their own set, and any time I make a change to the code that affects the CSS, I would have to make the same change in every client's CSS files. I was so happy when I realized that I could link a PHP file as my CSS - the performance difference from caching is minor; the risk of errors (and wasted time) if I had to maintain all those files is huge!

Jpadie: Is your comment related to the diagnostics question (sending $_SERVER from the faux CSS file to the session, and then using the main markup file to echo it) or the original issue? Hmm, would it really work out timing-wise to set a session variable like $_SESSION['filename'] right before the CSS link, and then pick that up in style.php? It feels kinda funny (asynchronous or something), but I guess the cart could not get before the horse (the CSS file couldn't run before the session variable's value was successfully changed to the current filename), and I can't think of a scenario where two files would get called at so close to the same time as to get their values confused before their respective CSS runs. Hmm, food for thought, as I have done some prep work for the big find/replace but haven't actually done the changes yet. Going to bed now, but I'll take a closer look in the morning.
 
After some testing, I think your are limited to the query string parameters, or session variables.

The problem is, since its being included as a stylesheet, the style.php script runs independently from the calling page, so there's no real link between them, to know who called it.

As feherke points out the HTTP_REFERRER header is the only thing you could use, but its not reliable as it can totally not be there.

To see what is inside $_SERVER within your style sheet, you can use Firebug. Just Expand the <head> section in the Firebug console, and then expand the <link>

Screenshotfrom2013-03-25092155_zps53b7010e.png





----------------------------------
Phil AKA Vacunita
----------------------------------
Ignorance is not necessarily Bliss, case in point:
Unknown has caused an Unknown Error on Unknown and must be shutdown to prevent damage to Unknown.

Web & Tech
 
Hi

Just one thought to add : ultimately you can manipulate the [tt]link[/tt] [tt]href[/tt] attribute with JavaScript too. Of course, the implementation, the efficiency and the success varies on where, how and in which order your JavaScript and CSS resources are included in the HTML document. I mentioned this just as a temporary solution, so you not have to refactor all 30 files right now.


Feherke.
[link feherke.github.com/][/url]
 
Jpadie: Is your comment related to the diagnostics question (sending $_SERVER from the faux CSS file to the session, and then using the main markup file to echo it) or the original issue? Hmm, would it really work out timing-wise to set a session variable like $_SESSION['filename'] right before the CSS link, and then pick that up in style.php?

the intent was to deal with both issues.
setting a session variable works fine anywhere in the main file.

Code:
if(session_id() == '') session_start();
$_SESSION['filename'] = 'something';
$_SESSION['debug'] = true;
session_write_close();

in the php css server
Code:
header("X-Content-Type-Options: nosniff"); //needed for IE from memory
header("content-type: text/css");
/*
potentially send cache-busters
*/

if(session_id() == '') session_start();
if(isset($_SESSION['debug']) && $_SESSION['debug'] = true):
  unset($_SESSION['debug']);
  //output debug information. 
  echo <<<CSS
/*
some debug information
*/ 
CSS;
  //or you could email it to yourself, or dump into a file
endif;
if (isset($_SESSION['filename'])):
switch ($_SESSION['filename']):
case '':
///output css
break;
default:
 echo defaultCSS();
endswitch;
 unset($_SESSION['filename']);
 session_write_close();

function defaultCSS(){
 return file_get_contents('path/to/default.css');
}
?>

just remember to delete the variables in the session and explicitly close the session too (to avoid race conditions).

you might also decide to send explicit cache busting headers to stop the content from being browser cached.

also it might be a good idea to call the css file in the html with a normal css extension and then use mod_rewrite to redirect the call internally to the php resource. not sure exactly why but something piques my memory about this being a good idea.
 
You appear to be engineering unnecessary complexity. The problem of color scheme inheritance you have described is not new and has already been addressed in mainstream web design concepts.

The same PHP you have prepared to inject live CSS on every page could be tweaked to write all necessary static CSS files to your server's filesystem whenever you update the template... so you don't need to be generating a new CSS file with each HTML page load. Then, all you would need your PHP to call is...
Code:
print ("<link rel=\"stylesheet\" type=\"text/css\" href=\"" . $clientmaster . ".css\" />");
print ("<link rel=\"stylesheet\" type=\"text/css\" href=\"" . $page . ".css\" />");

We can also use preprocessors like LESS and Sass to manage CSS color variables and generate static CSS files.

More on the problems with live, dynamic CSS...
 
Hmm, food for thought, as I have done some prep work for the big find/replace but haven't actually done the changes yet. Going to bed now, but I'll take a closer look in the morning.

if you go this route, post a query here first. you could write the find and replace in php in a few lines of code, and it would go and sort it out for you.

that way you could ... also change the reference to style.php to a php variable and have the variable replaced with the correct absolute URI on each page load, thus allowing cacheing but doing so intelligently and transparently; and offloading the effort from your php server to your webserver.
 
Once again, great contributions by everyone. I love the Tek-Tips community!

spamjim said:
You appear to be engineering unnecessary complexity.
Whether at runtime or in a pre-processor to make a unique set of static CSS files for each client, it will be the same amount of complexity, and as far as I can tell it is not "unnecessary". And I don't do everything wrong that was cited in that article you referenced - I'm not doing the insecure example, and I'm using the proper headers and such. Sure, it's faster to not invoke the PHP interpreter for one's CSS file, and caching is a help, but my files are really not that big (especially once I stop sending the stuff for other pages - the point of this thread). Without benchmarking it, I'm not sure whether the PHP engine use is more of a performance hit than having the browser ask for two files instead of one - if anyone has a gut feel on that, let me know, but there is a lot said about reducing HTTP requests (image sprites and such like that) but not much noise about minimizing PHP execution, so I wonder.

Anyway, there are far worse efficiency problems elsewhere in my code, and I plan a total rewrite at some point - I can work on tweaking this also at that time, and your idea of using the same PHP as a preprocessor to create a static CSS file is worth exploring. But right now the most limited resource in this whole thing is my time - I'm the sole developer of this monstrosity, and I'm only a missionary doing it as a part-time project, not a paid programmer (jpadie probably remembers this project, as he has helped me many times in the past).

vacunita: Thanks for the testing and info - you saved me struggling to figure that out. And the Firebug tip is helpful, too - I am a green novice when it comes to good use of Firebug.

jpadie said:
just remember to delete the variables in the session and explicitly close the session too (to avoid race conditions).
I already have a session that is used in every PHP file in my application (even the CSS one), for authentication and other information. I thought it closed at the end of script execution anyway - am I wrong? In this case I can close it when I have retrieved a few pieces of data at the beginning, but since it's not writing session data (only reading), I don't know how it would make any difference. I guess "race condition" is the how one puts into words that general unsettled feeling I had when I first thought of using the session for this. But I've tried to think of scenarios that could cause a collision, and I can't think of any - I don't do AJAX requests immediately upon pages loading (only in response to user actions). Plus, style.php will never write anything to the session - it will only read (unless I delete the variable after I read it). By the way, what is the purpose for your suggestion of deleting the variable each time (as opposed to just leaving it there and letting the next file overwrite its value)?

jpadie said:
also it might be a good idea to call the css file in the html with a normal css extension and then use mod_rewrite to redirect the call internally to the php resource. not sure exactly why but something piques my memory about this being a good idea.
Yeah, I need to learn more about how to utilize mod_rewrite - I think I'm missing out on simpler ways to do some things that it might be able to do, but that syntax always looks about as cryptic as regex expressions. Ah, so much to study! As to why that might be a good idea, perhaps its just a bit more security, not calling attention to the fact that my CSS file has code in it...
 
re race conditions, the potential is that style.php tries to read the current variables before page.php has closed the session. remember that (normally) a session store is just a file on a server. the processor has to get disk access, open the file, read it, write to it and then save it.

I hit race conditions the whole time when working on a local dev machine. not just in ajax requests, but in normal link clicking if the disk is busy.

the scenario that worried me was that if your webserver started pushing data before the pre-processing was finished. not abnormal. the browser might then receive the line with the css link in it before the pre-processor had finished, and as a result the browser might call style.php as a parallel process to listening for the rest of the html. In that scenario I see a genuine possibility of the session store being reopened by the code in style.php before the referring page has finished (and the relevant process then closes the session store). So i'd think it best to do the session processing before starting the output and then explicitly closing the session store (at which point the data is written - before then the data is not in the session although it is in the session superglobal for that thread).

as referred to in my previous post though, on balance I think it makes more sense to do the style nomination from within php on the html rather than rely on a php based css server.
 
jpadie said:
as referred to in my previous post though, on balance I think it makes more sense to do the style nomination from within php on the html rather than rely on a php based css server.
Okay, you lost me on this sentence - in the previous post from you, I thought your last sentence meant using a standard "<link rel="stylesheet" type="text/css" href="style.css" />" in page.php, with the session technique, and then doing something in mod_rewrite to change style.css into style.php. But the above sentence sounds like doing just an include for all the content, so the resulting markup to the browser has all the CSS inside a <style> tag.

Anyway, I'm losing interest in the session idea - if the session needs to be closed before the call to the CSS, that's starting to get too weird for my code, because I need session variables throughout my code, so I guess I would have to re-open the session later. At the moment (ignoring the above sentence I didn't understand), the idea of a GET parameter is sounding the most straightforward, even if not particularly classy-looking.
 
it is advisable to close the session to prevent aberrant behaviour. if you only read from the session store after closing it, you could simply do this

Code:
$tSession = $_SESSION;
session_write_close();
and then you can use $tSession afterwards.

but going back to my suggestion let's say you have a number of different css files that you need to choose between. and that these are chosen based on the value of a particular filename that is serving the main content.

Somewhere in your server side code you will know what or be able to calculate/determine which css file you should serve. When you know that (which of course should be before you start sending data to the browser), store the absolute uri (referenced to the webroot) in a variable.

then change all the <link> tags to be like this

Code:
echo <<<CSS
<link rel="stylesheet" type="text/css" href="{$stylesheet}" />
CSS;

then the right absolute uri will be inserted in place of the $stylesheet variable whenever php serves the webpage.

using this method you can put some code into a file that is _always_ called each time a resource is requested. such as a session initiator file. and because you will always have a meaningful request URI you should be able to make a sensible choice.

e.g.

Code:
switch (strtolower($_SERVER['REQUEST_URI'])):
  case '/somepage.php':
      $stylesheet = '[URL unfurl="true"]http://www.mydomain.com/css/mycss.css';[/URL]
      break;
  default:
      $stylesheet = '[URL unfurl="true"]http://www.mydomain.com/css/mydefault.css';[/URL]
endswitch;

i can post code to automate the search and replace to a variable for you.
 
jpadie said:
PHP:
$tSession = $_SESSION;
session_write_close();
That's a good idea for most of my code - only about 2-3 of my files write to the session at all (the login script and a couple others that change the GUI language and such), so it might be good for me to start a new habit of using this kind of technique to keep the session unlocked as much as possible.

jpadie said:
i can post code to automate the search and replace to a variable for you.
Thanks, but I think I can take it from here. There are other complexities that you know not of. [orientalbow]
 
just fyi, in a cli test i just did the $_SESSION superglobal remains populated even after session_write_close(). so you are free to continue reading from the variable.

you can also avoid the issue to some extent by storing session data in a database table against a session key. this is not the same as making the database table the session store (which suffers from similar constraints). but you would have a table that looks like this

Code:
sessionID varchar(20) primary key,
name varchar(255),
`value` longtext

and store the session variables in that table.

this could grow very big so you'd want to create a special garbage collector that would also delete table rows.

then instead of going $_SESSION['some variable'] = "some_text"; you'd do something like this

Code:
sessionStore('name', 'value');

function sessionStore($name, $value){
 global $pdo; //assume a pdo connection pre-exists in the global scope
 $s = $pdo->prepare("replace into sessionTable set value=? where name=? and sessionID=?");
 if(is_array($value) || is_object($value)) $value = serialize($value);
 $s->execute(array($value, $name, session_id());
 $_SESSION[$name] = $value;
}

or it would be easy to build and manipulate a session object from a class $session->name=value ; etc

that way there would be a much lower risk of race conditions and yet keep the classic session mentality.



 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top