Build a PHP Switcher

For your style-sheet-switching pleasure, A List Apart offers the
Switcher, a piece of
JavaScript that dynamically changes page styles. Functional as it is,
it quite unfortunately relies on the user to have both JavaScript and
cookies enabled. There’s not much we can do about the cookies, but we
can sidestep client-side processing with a little help from PHP.

Article Continues Below

PHP is a scripting language available on many, many servers. It’s
fast, it’s free, it’s open source and it handles everything on the
server side, so there’s no need to worry about users who have
disabled client-side scripting in their browsers. If you’re not sure
if your host has PHP installed, just ask them!

STAGE ONE: Setting styles#section1

The first step is to create a new file on your server named
switcher.php and paste the following code into it. (Line wraps are marked ». –Ed.)

<?php
setcookie ('sitestyle', $set, time()+31536000, »
 '/', 'yourdomain.com', '0');
header("Location: $HTTP_REFERER");
?>

When it’s queried, this file will write a cookie for the user
detailing which site style to use. The cookie is set to expire in one
year, and then the script sends the user back to the referring page.
All of this happens behind the scenes, so the user will never really
“see” switcher.php in action. To them, it looks simply as though
their page is refreshing. Don’t forget to put your own
“yourdomain.com” into the script, or your cookie won’t be valid.

Telling switcher.php which site style to use is an equally simple
matter. You can query it using conventional HREF links in text,
images, or even flash. All you need to do is write a link to
switcher.php and append a query string defining the style sheet you
want.


click here to change to RED style!

In the above case, “red” is the name of the style sheet you want to
use. There’s no need to append the .css file extension here; that
gets done later. The link calls up switcher.php and tells it to use
“red”, leaving the switcher to do the rest. As an alternative to HREF
links, you can use form elements to select and set your style sheets.
Try this drop-down menu:

<form acti method="post">

<option value="default" »
 selected>Default
Crazy Red
 »
 Experimental Style

<input type="submit" value="Change Style">
</form>

STAGE TWO: Detecting styles#section2

It’s all very well and good to allow users to choose styles and have
cookies written for them, but without a cookie detection script, the
whole system falls on its face. So for every page of your site that
you want to use user-defined style sheets, paste this next piece of
code into the <head>.

<link rel="stylesheet" type="text/css" 
 media="screen" title="User 
Defined Style" href="<?php echo 
(!$sitestyle)?'defaultstyle':$sitestyle ?>.css" />

You’ll notice that this is a normal <link> element, the kind you’d
use to include any standard CSS file, but there’s an important
difference; where you’d normally write the name of your style sheet,
we’ve used:

<?php echo (!$sitestyle)?'defaultstyle':$sitestyle ?>

This tiny script detects which style is in the user’s cookies and
prints out the result. If the user doesn’t have cookies enabled, or
just hasn’t chosen a site style for themselves yet, the script will
default to “defaultstyle.css”. Feel free to change
“defaultstyle” to whatever your default CSS file is named.

So there you have it. A cross-browser, backwards-compatible,
forwards-compatible, standards-compliant style sheet switcher in just
five lines of code. It’s fast, straightforward, and universally
accessible because there’s no processing done on the client side. For
the Geckophile in you, you should also make reference to your
alternate style sheets within the document <head>:

<link rel="alternate stylesheet" 
   type="text/css" media="screen" 
   title="Fire Engine Red" href="./redstyle.css" />
<link rel="alternate stylesheet" 
   type="text/css" media="screen" 
   title="Grape" href="./purple.css" />
<link rel="alternate stylesheet" 
   type="text/css" media="screen" 
   title="Scary" href="./blackout.css" />

Though not necessary, listing your alternate style sheets in this way
enables users of the Gecko browsers (Netscape 6+, Mozilla 1+) to
change style sheets from within the browser interface. All they need
to do is go to View > Use Stylesheet and pick which one they’d like
to use.

That’s it. Get out there and style!

About the Author

Chris Clark

Chris Clark is a confirmed HTMinimalist who likes long walks, CSS and standards compliance. When he’s not fretting about download times or his WAI rating, he’s tinkering with his online playground at decaffeinated.org.

87 Reader Comments

  1. > setcookie (‘sitestyle’, $set, time()+31536000, ‘/’, ‘yourdomain.com’, ‘0’);
    If $set is to contain the HTTP GET variable from the query string, use
    $_GET[‘set’]. This is the preferred way of working with client input from the query string. Old style PHP works fine as the example is, but newer versions probably have register_clobals off, meaning input is separated:
    $_GET
    $_POST
    $_COOKIE
    $_REQUEST (all of the above)
    $_FILES (uploaded files using POST)
    $_SERVER (user AND server variables, e.g. HTTP headers, environment variables)

    Here’s some nitty gritty from the PHP documentation:
    >In PHP 4.2.0 and later, the default set of predefined variables which
    >are available in the global scope has changed. Individual input and
    >server variables are by default no longer placed directly into the global
    >scope; rather, they are placed into the following superglobal arrays.

    Apart from that, of course, it’s a nice article. Good to see ALA going more developer-ish again. 🙂

  2. A server side stylesheet switcher would appear to suffer from the same proxy-caching issues that affect server side browser sniffers.

    For example, an AOL user could visit your site and switch to the “red” style sheet. A copy of the page with the following style sheet link would be cached on AOL’s proxy server.

    The next time an AOL user came to your site, they may be served the page with the red style sheet from the AOL cache regardless of their cookie value.

    You should be able to avoid this problem with the following lines of PHP code at the top of the page you don’t want to be cached.

    Header(“Cache-control: private, no-cache”);
    Header(“Expires: Mon, 26 Jul 1997 05:00:00 GMT”); //Past date
    Header(“Pragma: no-cache”);
    (pilfered from http://php.weblogs.com/stories/storyReader$550)

  3. A suggestion:
    Instead of putting the PHP to select which stylesheet to use in every page, wouldn’t it make more sense to do something like this: and then have styleredirect.php redirect to the appropriate stylesheet? That way, you could have one copy of the code instead of scattering it throughout every page of your site. It would make maintenence much simpler. Unfortunately, I don’t know PHP, so I’m not entirely sure how to actually code this.

  4. > header(“Location: $HTTP_REFERER”);

    This wont work when users are using proxies or web browsers that they
    configured to not to allow the webserver to read the referer-information
    (for privacy / security reasons).

    For example, I only need one click to turn off referer logging in Opera 6
    http://schechtel.de/pub/screens/2002/1013-opera6-referer-turn-off.gif

    In such cases the user will see a blank page (in the best case).

    Just FYI.

    Greetings from Germany,

    Roman Schechtel

  5. I use the code below and use JavaScript to set the cookie. Add more cases for more style sheets.


    < ?php header ("Content-type: text/css"); ?>
    /* Style sheet */

    < ?php switch (isset($style) ? $style : "Default") { case "Blue": echo "@import "blue.css";"; break; default: echo "@import "regular.css";"; } ?>

  6. This script has a potential security flaw – an HTML injection attack. The script embeds HTML in to the document directly from the query string of the page without first checking that the HTML is “safe”. This could allow a crafty cracker to steal your browser’s cookies for the site, which could lead to a security breach if cookies are used to store administrator sessions (for a content management system for example). As a lesser evil, it could also let malicious third parties to add inapropriate content to your site as viewed by another user.

    Here’s (roughly) how it would work. A cracker tricks someone in to visiting your site with a URL that looks like this:

    http://yoursite.com/switcher.php?set=“>

  7. It is amusing to see that trick here a year after I used it, and looking back, it shows that I too didn’t sanitise the querystring value that was passed to the switcher.

    Here’s a simple sanitiser that will remove all non-alphanumeric characters, and also get $set The Right Way ™:

    < ?php $set = $_GET['set']; $set = preg_replace('#[^a-zA-Z0-9_-]#', '', $set); setcookie ('sitestyle', $set, time()+31536000, '/', 'yourdomain.com', '0'); header('Location: '.$_SERVER['HTTP_REFERER']); ?>

    One drawback of this technique is that if there are any websites’ pages in the browser’s history AFTER your website’s page, they’re just *poof* gone when the switcher link is clicked.
    (Then again, that was the case with last year’s browsers, maybe by now they implemented a check for 0 bytes pages not to be included in the history.)

  8. Was the reference to that URI at the end of the article some sort of joke I did not get?

    A page which does nothing and has no links surely would not be much of a worry as far as WAI rating…

    Brett

  9. Brett, if you checked the source code you would see that decfafeinated.org is ‘returning soon’. Apparently it has gone off line until further notice.

    A question about security: How serious an issue is the security breach, and how easily accessible is it to get to the cookies?

    I keep wanting to get into PHP, but there always seem to be serious security issues. Any commentary on this would be appreciated.

    Thanks.

    Marty

  10. Marty, the most this security breach (that the sanitised version of the code avoids) could do is get the cookies from the website the PHP switched is on. However, this is only if using javascript. If you passed some PHP code in the querystring value, you could do much more than that.

    There really aren’t security issues with PHP itself, it’s only that’s it’s very easy for unexperienced people to produce insecure code.
    Eventually, it all comes down to the good “never trust the user” doctrine, and the systematic sanitisation of user-submitted data. Once you start following these simple rules, your PHP will be as secure as can be. 🙂

  11. The security breach I described is only a significant problem if you run a site that has a cookie-powered login for an administration panel – as is the case with most web based content management systems. Sites that do not use cookies in this way are not nearly as badly affected – a malicious third party could still “trick” someone by adding content to your site temporarily (through adding it to the query string and tricking someone in to visiting the site via that URL). Michel’s sanitiser is a good way of avoiding this – I tend to use PHP’s htmlentities() function for the same purpose.

  12. Cheers, that’s a helpful article, but one little meta-gripe. It’d be nice if i could make the small text larger in ala articles by choosing View -> Text Size -> Larger [IE6/Win2002]. Jakob N would roll in his grave (if he were dead).

    cheerio

  13. OK… No, I haven’t used PHP before… and this seemed like such a perfect idea since I have a client going live in two days thought wants accessibility and styleswitching. I was attempting to use this as a “no javascript” method of doing this.

    I contacted my host who said that PHP was now enabled for the site… followed the directions in the tut… and ended up with a completely unstyled page. 🙁 When trying it in Mozilla, I do see the option of “other stylesheets” and can even choose the one I have as an alternate… but not with the PHP switcher…

    Has anyone been successful with this article? Is it missing anything? I even tried the code in Michel V’s post above and now I’m getting an error that says:

    Warning: Cannot add header information – headers already sent by (output started at /home/sites/site171/web/testing/switcher.php:2) in /home/sites/site171/web/testing/switcher.php on line 5

    Warning: Cannot add header information – headers already sent by (output started at /home/sites/site171/web/testing/switcher.php:2) in /home/sites/site171/web/testing/switcher.php on line 6

    So is it hopeless? Or is there some little errata… or am I just “not getting it?” It has been a long day. 😛

  14. It should be mentioned that you should not:

    setcookie (‘sitestyle’, $set, time()+31536000, ‘/’, ‘yourdomain.com’, ‘0’);

    As was mentioned, the variable $set can be made to be anything (including bogus HTML) and that information would then be saved to the clients machine. In circumstances beyond what was discussed above, I’m not sure that this is a big deal, but you’re allowing external sites to set cookies for your site this way.

    One thing that immediately popped to mind is that you should check the referer. There could be problems with proxy servers (as was mentioned), but if you check the referer to see if it is YOUR server, then you are better off. Also you may check the value of $site against some “acceptable” names like “red”, “blue”, “green” like this:

    $acceptStyle = array(“red”, “blue”, “green”);
    if(in_array(trim($site), $acceptStyle)){
    // set the cookie here…
    }

    Also, in general, always use the “superglobal” variables ($_REQUEST, etc.) when getting data from users, not the variables that are automatically created through register_globals.

  15. I think it’s kind of neat to see code in the article almost identical to what I’ve done before with this. Great minds, right? In fact it gave me reason to dig out the script of the site it’s on and clean it up a bit, incorporating all the suggestions made thus far as well as more modern PHP coding techniques. Until I saw it here:
    http://www.contrastsweb.com/switcher/
    Again, it’s eerie how similar the code is. I’m going to start reading Rob’s blog because it’s nice to find someone who thinks similarly. I would recommend the code above, with only two minor changes based on experience I’ve had.

    First, Netscape (bah!) has trouble with cookies whose domain has less than two periods in it. The nice way to fix this is to write your domain like “.example.com” (note the leading period!) which also has the nice side effect of making the cookie valid for any sub-domains you may have. Even if you don’t use sub-domains, this allows the same cookie to be used for people accessing your site through either yourdomain.com or http://www.yourdomain.com.

    I’ve also had trouble with PHP’s built-in setcookie function, so if that’s giving you trouble, you can always fall back on using straight headers to take care of things. Such as:
    header(“Set-Cookie: theme=$theme; path=/; domain=.photomatt.net; expires=”.gmstrftime(“%A, %d-%b-%Y %H:%M:%S GMT”, time()+10960000));

    For more information on cookies in general, and for a little trip down memory lane, check out the original cookie specification from Netscape at http://wp.netscape.com/newsref/std/cookie_spec.html. Partly I think because of their sadly lacking version 4 release, people forget how much Netscape really expanded technology behind the web. Sometimes for better, sometimes for worse. On that same vein it’s not a flaw in PHP that allows things like injection attacks, but rather coding that doesn’t consider as many possibilities as possible. I’ve found that coding for security in turn makes my code cleaner, more maintainable, and less likely to have to be rewritten after a while. Think of it as forward compatibility on the backend 🙂

    Meta: Could someone take a look at the regex (or whatever) is parsing the URLs for the forums? It works fine with most everything, but chokes on a few notable common URL characters.

  16. Arg, it ate the period in the URL I posted above, here’s a clean version:
    http://wp.netscape.com/newsref/std/cookie_spec.html
    That’s really my fault though; I should have put a space after the URL. Maybe it would just be easier to allow *just* anchor tags. The web is all about links. Sanitizing for one tag should be fairly trivial as well. Another solution would be the option to preview a post, so you can tell how things are going to turn out.

  17. One solution to the problem with using $_SERVER[‘HTTP_REFERER’] would be to send the current URL to switcher.php along with the stylesheet like this:

    switcher.php?set=red&ref=< ?=$_SERVER['PHP_SELF']?>

    Then use $ref instead of $_SERVER[‘HTTP_REFERER’].

    Stephanie: You get those errors when you try to call the header() function after some html has been sent to the browser. Make sure that you don’t have any content (even a single space) before your opening

  18. Alan, that’s just to ensure the script gets data that it could still use. If someone uses the evil.js method that Simon showed, strip_tags() will still put a remaining closing angle bracket as a cookie, and that can break the HTML that the page produces.
    Just removing anything that’s not alphanumeric ensures that the cookie set in the evil way isn’t going to break the HTML 🙂

  19. OK, this is probably showing some ignorance on my part, but doesn’t this method (stage two, detecting styles) require all pages using the switcher to be parsed by php? A < ?php echo (!$sitestyle)?'defaultstyle':$sitestyle ?> in a “link” tag isn’t going to be executed in a plain HTML page unless the server is configured to have PHP parse .html as well as .php, right? And mod_perl pages and other things with their own handlers wouldn’t do anything with PHP instructions either. Am I missing something?

  20. You aren’t missing anything. The PHP snippet to echo the stylesheet name requires the page to be parsed as PHP.
    But it’s possible to achieve the same effect with JavaScript: read a cookie named ‘stylesheet’, if it doesn’t exist, make stylesheet = a default string. “This is left as an exercise for the reader.” 🙂

  21. There is more chance that a user will have cookies disabled than JavaScript disabled. All the above will not work without cookies.
    I am using SESSIONS in my version, this script assumes that PHP 4.2+ is installed and that register_globals is off with –enable-trans-sid.

    Code as below:

    < ?php session_start(); ?>
    < ?php if(isset($_GET['css'])){ switch ($_GET['css']) { case 'css1': $stylesheet = '‘;
    $_SESSION[‘csschanger’]=$stylesheet;
    break;
    case ‘css2’:
    $stylesheet = ‘‘;
    $_SESSION[‘csschanger’]=$stylesheet;
    break;
    case ‘css3’:
    $stylesheet = ‘‘;
    $_SESSION[‘csschanger’]=$stylesheet;
    break;
    case ‘css4’:
    $stylesheet = ‘‘;
    $_SESSION[‘csschanger’]=$stylesheet;
    break;
    default:
    $stylesheet = ‘‘;
    $_SESSION[‘csschanger’]=$stylesheet;
    }
    }
    ?>
    < !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


    CSS Changer

    < ?php echo ($_SESSION['csschanger'])? $_SESSION['csschanger']: '‘ ;?>


    ?css=css1″>Stylesheet 1
    ?css=css2″>Stylesheet 2
    ?css=css3″>Stylesheet 3
    ?css=css4″>Stylesheet 4

    As an extra, for future visits, you could of course set a cookie as well, but this method would not need cookies or JavaScript to work during the users SESSION. If cookies were disabled, then the SID would be passed with the URL, or you could even code the SID in if enable-trans-sid is not compiled on your server.

  22. Thank you, Peter Hawkes! This is exactly what I was hoping to find, and even better, it works. PHP rocks.

    For those still using older versions of PHP:

    change $_GET to $HTTP_GET_VARS
    change $_SESSION to $HTTP_SESSION_VARS
    change $_SERVER to $HTTP_SERVER_VARS

    thanks again. cheers, Robert Roberts

  23. The person who suggested PHP be put in the CSS document was real close – you can’t put PHP inside a .css file, since .css isn’t parsed by PHP unless you set it to, so here’s an easier trick:

    Use a CSS document name of .php – the file will (haven’t tested this, but it makes sense) be parsed by PHP before being shipped off to the client when they request it. As long as you make sure to define it as text/css, the browser shouldn’t care about it’s extension.

    In the .php file, just put all the code you need to do your dirty work. Oh and a tip for this… don’t use cookies with long expiry dates – set the expiry time to 0, which will make it die as soon as the browser closes (at the end of a “session”). Also, as mentioned before, don’t let people set whatever they want 🙂 Whenever you accept user input, you have to take every precaution imaginable to prevent someone mis-using your scripts.

  24. One week after I’d finished my own version of this it appears here. Never mind.

    My version is different in that it doesn’t use GET variables to set the cookie. At the moment my switch-style links point to locations of the form: /ui/configure/”style-to-apply”/. Whilst this means that at the moment I am having to put code in each subdirectory it does mean that the only way to do an HTML insertion attack is to change the actual value of the cookie.

    Whilst this is not the best solution to the problem it avoid the injection attack. One way to make the code easier to maintain would be to use the techniques from http://www.alistapart.com/stories/succeed/ the mod_rewrite article to redirect requests to the subdirectory to a script that could encode the correct cookie.

    Just a thought. Great article, can’t wait for next weeks.

  25. >>>>>>
    In the .php file, just put all the code you need to do your dirty work. Oh and a tip for this… don’t use cookies with long expiry dates – set the expiry time to 0, which will make it die as soon as the browser closes (at the end of a “session”).
    >>>>>>

    what would be the point of using a cookie then if you’re setting it to 0? If that’s the case then you should be using a session variable instead.

  26. what would be the point of setting the cookie to 0 ?? If you want it removed at the end of a session , just use a session variable instead.

  27. What’s the point of having ‘save’ on the file menu? It gives you different ways of doing the same thing.

    Also, regarding the suggestion that, without checking, a malicious user could run their own PHP code: not possible. For this to happen, the script must contain an eval() statement or something that uses unchecked user input.

  28. where the example uses (!$foo) ? ‘default’ : $foo

    it would be much clearer to simply write

    $foo ? $foo : ‘default’

    because then you don’t have to parse the negation as well, and neither does the computer.

  29. Is it possible to have the currently selected choice not linked –
    meaning, if i’m at red there is no reason for me to be able to
    click on “red.” the text could still be there as an indicator
    of the current choice. I just thought of that, but have no idea how to do it in PHP or if it could be done, but if it could that’d be pretty cool.

  30. There is no easy way (that I know of) to de-link the current link. The non-easy way is to generate you links for each page. Include a seperate file in each page that contains you navbar code. When you want to generate the style links then something along these lines would work (pseudo-code):

    $styleNamesArray = (“style1”, “style2”, … , “stylen”);
    foreach ($styleNamesArray as $styleName)
    {
    if ($styleName = $_COOKIE[‘styleCookie’])
    {
    echo $styleName;
    }
    else
    {
    echo “$styleName“;
    }
    }

    Something like that anyway.

  31. Good advice. mr. anonymous

    Using gets around the requirement of having every page on the website parsed by php. Only 2 pages need to be parsed, instead. Just be sure to include:
    header(“content-type:text/css”);
    in the php script before you output anything else.

    One suggestion for getting around relying on the $HTTP_REFERRER tag is to use a javascript to call the switch.php?set=red script, as the src for a hidden image.
    or some such typing (I’m not very good with JS). Or, make the image non-hidden, and actually have the stylesheet.php return an image based on the selection. Could have some fun with this.

  32. I just wanted to say w00t!~ and thanks to all for your suggestions.

    I was trying to find an alternative to javascript not cos of people having it disabled, but because of a conflict between something I had just implemented and the window.onload of the old ALA switcher …

    I’ve remodelled my site in PHP recently, so this was the next logical step!

    Thanks for the session-level piece-of-code … that makes my site just perfect!

    Cheers!

  33. Boyd: Maybe not, but you could tell for sure by adding three lines of code to switcher.php. This would also have the advantage of showing which URL and style people preferred. In fact it could even catch any would-be hackers so you could ban them. If you wanted you could also add browser, host, and time.

    $fp = fopen(“elog.txt”, “a”);
    fwrite($fp, “$REMOTE_ADDRn$HTTP_REFERERn$setn———-n”);
    fclose($fp);

    Add that, then create a log.txt and chmod it appropriately. True, it’d be relatively slow and byte intensive but you could use it for a short period of time just to measure user responce. As for a MySQL version, I’ll leave that as an excercise for the reader… 😉

  34. Oops, in my previous post I made two mistakes:

    A. $fp = fopen(“elog.txt”, “a”);
    should be $fp = fopen(“log.txt”, “a”);

    and

    B. I forgot to fill in name.

  35. i just add a bit of mail code to test if theses things are used – and they rearly are, very few user ever do anything but the very basics.

  36. Yeah – try adding the following onChange in your

  37. I have discovered a small (massive) problem with the “session-level” code proposed earlier in this thread …

    It will not validate! Aarrgh … is there any way to force the &PHPSESSIONID=blahblahblah… to use &PHPSESSIONID=blahblahblah … instead ?

    I love this bit of code, but this is a pain!

  38. A couple of things.

    First if you are already parsing pages to add the styles then there’s no reason not to put the cookie code right into the page itself instead of using another (switcher) page.
    (I know about the new _GET var but I’m not using it quite yet in shared code because not everyone has upgraded their php yet)

    if ($set || $HTTP_GET_VARS[‘set’]) {
    setcookie (‘sitestyle’, $set, time()+31536000, ‘/’, ‘yourdomain.com’, ‘0’);
    $sitestyle = $set;
    }

    simple enough no extra pages and bouncing around. Someone else has already mentioned the inheirent security issues. This hack has been availible in almost every PHP tutorial on this site. If you are going to write server side coding tutes please know some basic security concerns before opening newbies up for attacks.

  39. Returning CSS from a .php file is not trivial.

    Make sure you are specifying the cache headers manually, otherwise every page hit will also have to fetch the stylesheet all over again. The default is to not cache dynamic pages.

    More importantly, some browsers are borken and won’t work with a .php URL even if the ContentType is text/css.

  40. Ok, just about got this to work (website in development stage, still!). What I would like to do, and could with javascript using the styleswitcher in ALA 126, was to display the name of the style in use, and parse the filename to a link enabling the user to validate the stylesheet in use via W3C’s validator. (didn’t work in Opera tho. huh!)

    Any ideas on doing the same with PHP?

  41. Stephanie –

    This error:
    Warning: Cannot add header information – headers already sent by (output started at /home/sites/site171/web/testing/switcher.php:2) in /home/sites/site171/web/testing/switcher.php on line 5

    Is often caused by having whitespace at the beginning or end of your php file. So take out any whitespace (tabs, spaces, newlines) from the PHP file, and that *might* fix it. The general idea here is that *nothing* can be output before calling the header() function (not even whitespace).

    For more info see the PHP manual page on the header() function:
    http://www.php.net/manual/en/function.header.php

    – Mike

  42. Hello All,

    I am also new to php so, please bear with me…
    I would like to use this php code to enable a style switcher on my site. My purpose for a style switcher is not for the user to pick a new style bc in my humble opinion most users dont really care. I would like to use it for styles to switch when different browsers are used to view the page. So, if a user opens a page with ie the php code recognizes that the browser is IE and loads the page with the title “ie” or “ns” or “opera” in the link rel tag.

    thanks for the help, simeon

  43. You can use this …

    //-->

  44. Slightly off topic but I figure here’s a good place to get an answer…

    I have two alternate stylesheets with opposing rules set up on a switching method. This switch works fine in IE but not in NS.

    /* Stylesheet 1 */
    /* —————————————————– */
    span.metric { display: inline; }
    span.imp { display: none; }

    /* Stylesheet 2 */
    /* —————————————————– */
    span.metric { display: none; }
    span.imp { display: imp; }

    It should be obvious what I’m trying to achieve (two adjacent span tags with metric and US customary units), however when NS disables both alternates and then enables the desired alternate both tags fail to display, rather than the ‘switching’ behaviour desired (and working in IE).

    Can anyone throw some light on this?

  45. Whoops – typo in post. The switch does not work.

    /* Stylesheet 2 */
    /* —————————————————– */
    span.metric { display: none; }
    span.imp { display: inline; }

  46. Made a workaround using with internal attributeNodes for metric and imperial values, and a script to change the childNode accordingly.

    Not quite as good as if it were totally driven by CSS, but at least it works in the DOM compliant browsers – and non-compliants just get stuck with the default metric, so it’s not all bad.

  47. I have something just like this, using sessions and PHP, but I also have control-blocks scattered at intervals in the source-framework to do special modifies at special designs, not just CSS.

    Try switching from one design to another, and view source for all of them; they’re kinda the same, but also not quite, depending on the design. The writing of these extra style-HTML is very easy, and stored away in separate files and functions.

    But it sure will take a lot out of your servers resources when many come alookin’, though. Beware.

    Alex

  48. I’ve tried to use the PHP Styleswitcher, but it doesn’t seem to work. I’m a PHP novice, but worked through the example and tried it. The URL is http://www.themmgroup.com/example.php

    I checked the source of the executed PHP file and it says:

    Warning: Undefined variable: sitestyle in d:websitesvirtualwebsthemmgroup.comexample.php on line 7

    Dunno what I’m doing wrong! My ISP is using PHP Version 4.0.4pl1. Is this a problem?

    Thanks

  49. Richard some configurations will choke on this line

    ?php echo (!$sitestyle)?’defaultstyle’:$sitestyle ?>.

    if $sitestyle is not set at all. Try switching the line to this.
    < ?php $sitestyle = (!isset($sitestyle)) ? "defaultstyle" : $sitestyle; echo $sitestyle; ?>

  50. In reply to the poster Natcher00 about not validating due to the & in the PHPSESSID, simply add the following to yopur .htaccess file:


    php_value arg_separator.output “&”

    Now PHPSESSID is appended with & and not &

    Pete 🙂

  51. The problem with using php in a css file is that you lose the benefit of the client’s browser caching the css file after a single access. Now that the css file is dynamic, the browser will have to download it again each time a page is viewed. So you may want to keep your core css in a static cacheable .css file and the few scripted parts in a small .css.php file. This saves bandwidth for everyone, woo!

  52. I would’ve jumped in earlier, except that I don’t read here very often. My bad.

    I’ve had a tutorial up on PHP + skinning for over a year here: http://www.domesticat.net/skins/howto.php

    It’s interesting to see that other people are interested in this particular bandwagon.

    One thing that I did differently than everyone here, it seems, is make each skin’s name numeric. (I currently have seventeen.) Keeping the names numeric means that I can run a very specific set of checks on the requested value of $skin (is it a positive integer? is it within the range of numbers I specify?) and drop the user back to a default skin if their requested value of $skin is invalid.

    In some ways what I’m doing goes a bit beyond the scope of this discussion; I’m using the value of $skin to do more than just swap a stylesheet. There are a lot of extras available on my site that are just a bit too much for those using modems, lynx, or handhelds, so there are superslim versions of the site geared toward those devices.

    Most of the tutorial has more to do with preparing your site for skinning purposes, and most of it’s utter common sense. Perhaps it’ll help someone in the future.

  53. Great article!

    I tried it out and got it to work after a short while. The only problem is: the cookie doesn’t get written in NN4 and so the whole switching thing fails in that particular browser.

    Does anyone have a clue why? I’d love to hear it 🙂

    Cheers Martin

  54. I know this forum has been dead for a while but hopefully one of you PHP heads is still checking it out. I use an SSI tag to include a navbar, and I was able to do that in my index.php file using a php include statement. (because apparently regular SSI tags won;t work here). THe problem is, none of the css styles get applied to the included navbar, which I tried as an html, a php, and I even tried adding the stylesheet select code that goes in every page to no avail. I hope someone can help; I’m not sure how to fix this.

  55. ok disregard the previous post, I figured it out. It may have been a simple thing to most but when you simply don’t know PHP other than what you copy and paste…..

    At any rate I’m having a smaller yet similar problem. I used the following to include my nav.php –

    < ?php include("nav.php"); ?>

    And then in the nav.php we have

    < ?php echo ("Home | “);
    echo (“
    Sights | “);
    echo (“Sounds | “);
    ?>

    The CSS switcher DOES affect these links as they appear on index.php through a browser, but the applied CSS style does NOT affect the pipes (|) that are in between the links here. I know it seems trivial, but not only do I want the pipes to appear correct, eventually I may add more to the nav bar, like a table to hold the links, or other non-link text. Please help

  56. I noticed that without cookies enabled this whole thing fails to work. I guess this was obvious but I had originally thought that setting the cookie was simply so that the user came back to his or her chosen style. Is there a workaround that allows the switcher to still work if cookies are disabled or is that just how it is?

  57. Yes, look at previous posts.

    There were a lot of suggestions and samples to achieve this using SESSIONS. Haven’t looked into it myself but will certainly do as I get more into PHP.

    Cheers Martin

  58. I *HAD* it all working on my blog (MT on Apache2/PHP4.3.0) and after one day and a couple of index-rebuilds it was all gone… 😕 The switcher.php wasn’t working (anymore): the browser kept on that page and didn’t return to index.php with a new stylesheet.
    Now I see a lot of suggestions here but I miss a complete solution e.g. not just rewrites of some possible buggy rule in switcher.php 🙂
    Anyone PLEASE? TIA!

  59. I wish that there was a way of doing this using ASP. I know, I know, PHP is better, faster, etc. The problem is, my ISP doesn’t have PHP installed, and only supports ASP. The website I’m working on (see URL) is entirely authored in standards-compliant xhtml and css, and I just wish I could take advantage of that.

  60. But I’d imagine it was possible, no?

    I did it with ColdFusion myself. Yes, a few minutes of downtime at work.

  61. but using sessions, it wont save the users theme will it? cause each time they go the site, they will view the default theme, wont they?

  62. If this works, and I guess it does, then why doesn’t AListApart use this in addition to the Javascript solution. If they used this as well (instead of an empty response on the buttons) then Opera users could switch styles as well…

  63. i tried this a short while ago, and it didn’t work for me in netscape. to get around it i tried adding AddType application/x-httpd-php .css to .htaccess, and keeping the .css extension, which for some reason also didn’t work in netscape, although IE was fine (never tested opera). never did find out why =.

  64. I’m using this on my blog website http://www.slowchildrenatplay.org/ and it works fine in IE 5.5, IE 6 and Netscape 6.2. When I try to change the styles in Netscape 7 though, I have some trouble. When I click one of the style-changing links, the browsers goes to http://www.slowchildrenatplay.org/switcher.php?set=style but doesn’t refresh… it stays there, looking blank. If I hit the back button and refresh the index page, the new style is applied. Does anyone know how this switcher works with NN 7? Can someone look at my code and see if I made a mistake? (I’ve double checked a few times, and everything appears to be in order.)

  65. If you use $SERVER_NAME instead of ‘yourdomain.com’ then you don’t have to type in your domain name and virtual hosts, will all work…

    Also I do my switching like so:-

    if have a directory with css files in (amongst other things…)
    so include the following from a php library file:

    function getCssFiles($dirPath)
    {
    if ($handle = opendir($dirPath))
    {
    while (false !== ($file = readdir($handle)))
    if ($file != “.” && $file != “..” && substr($file,-4) == ‘.css’)
    $filesArr[] = trim( substr($file,0,strlen($file)-4) );
    closedir($handle);
    }
    return $filesArr;
    }

    //load the css file names into an array
    $CSS = getCssFiles($CONFIG[“HomeDir”].”inc/”);

    then when i want to include the css file name
    $template is a variable pulled from a cookie or query…

    $key = array_search($template,$CSS,true);
    if ($key !== FALSE) { $usethis = $template;
    else { $usethis = ‘default’; }

    so there you go…

    its all automatic, no list/array maintainence. You can add/remove css on the fly. and it has secuity to stop dodgy inputs, if the css is not on the list, your not coming in 🙂

    btw, nice work ALA i like what your doing!

    [Hilarious joke, envolving future thinking, to inspire the world and keep the web ‘live’ :]

  66. Thank you for putting up a complete example for a novice like me! i spent 12 hours straight playing with this idea and it wasnt till i used your example that i got everything to work beautifully! THANX!

  67. I’m trying to use the code on the first page of this forum dicsussion but it doesn’t work. It doesn’t change the css, jsut stays with the default one.

    The server has register_globals on, but enable trans_id is enabled. It’s php 4.3.2. Could this be the problem?

  68. sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss

  69. Hi there, I’m trying to use this code to switch styles on my website. I have used ALA’s Javascript switcher before, and it worked. But I can’t get the PHP version to work! I followed the tutorial step by step, and checked everything I could. It just shows plain text without any stylesheet (even if I let it show the default one). My server runs PHP and other scripts work perfectly.

    Can anyone please help me? Greetings from the Netherlands,

    Nick

  70. I tried to implement the code given by Peter Hawkes and all works fine after the first click… the first time visiting the page, I get:

    Notice: Undefined index: csschanger in c:hostingwebhost4lifememberbraincreseannewindex.php on line 32

    anyone know why?

  71. I am using the switcher by peter hawkes:

    here is more chance that a user will have cookies disabled than JavaScript disabled. All the above will not work without cookies.
    I am using SESSIONS in my version, this script assumes that PHP 4.2+ is installed and that register_globals is off with –enable-trans-sid.

    Code as below:

    < ?php session_start(); ?>
    < ?php if(isset($_GET['css'])){ switch ($_GET['css']) { case 'css1': $stylesheet = '‘;
    $_SESSION[‘csschanger’]=$stylesheet;
    break;
    case ‘css2’:
    $stylesheet = ‘‘;
    $_SESSION[‘csschanger’]=$stylesheet;
    break;
    case ‘css3’:
    $stylesheet = ‘‘;
    $_SESSION[‘csschanger’]=$stylesheet;
    break;
    case ‘css4’:
    $stylesheet = ‘‘;
    $_SESSION[‘csschanger’]=$stylesheet;
    break;
    default:
    $stylesheet = ‘‘;
    $_SESSION[‘csschanger’]=$stylesheet;
    }
    }
    ?>
    < !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


    CSS Changer

    < ?php echo ($_SESSION['csschanger'])? $_SESSION['csschanger']: '‘ ;?>


    ?css=css1″>Stylesheet 1

    ?css=css2″>Stylesheet 2

    ?css=css3″>Stylesheet 3

    ?css=css4″>Stylesheet 4


    BUT.. Is there a way of doing it so it validates??

    I have put this code as one file and used then included it each page.. can i change the style changer links to something like :
    at the end… THIS DOESN’T SEEM TO WORK FOR ME.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

Nothing Fails Like Success

Our own @zeldman paints the complicated catch-22 that our free, democratized web has with our money-making capitalist roots. As creators, how do we untangle this web? #LetsFixThis